web-dev-qa-db-fra.com

Conversion RVB "standard" en niveaux de gris

J'essaie d'écrire un algorithme de conversion qui prend une image JPEG et renvoie sa version PGM (Portable Gray Map). Le problème est que je ne comprends pas comment fonctionnent les convertisseurs "officiels" JPG-> PGM en termes de valeur à attribuer au pixel final (je suppose, 0-> 255) à partir du format RVB classique.

Au début, j'ai utilisé cette formule (c'est la même que celle utilisée par la conversion CV_RGB2GRAY d'OpenCV):

0,30 * R + 0,59 * G + 0,11 * B = val

J'ai écrit un code simple pour tester mes résultats: il prend une image couleur et sa version PGM (déjà convertie avec GIMP). Il convertit ensuite l'image couleur en utilisant la formule précédente. Le but est d'avoir une image en niveaux de gris qui est pixel à pixel égale à l'entrée PGM.

À ce stade, il ne renvoie pas les mêmes valeurs. Pouvez-vous m'aider?

17
TheUnexpected

Le problème est que je ne comprends pas comment fonctionnent les convertisseurs "officiels" JPG-> PGM en termes de valeur à attribuer au pixel final (je suppose, 0-> 255) à partir du format RVB classique.

Il y a probablement un ajustement gamma dans la conversion que ces outils "officiels" utilisent.
Autrement dit, ce n'est pas seulement une transformation linéaire.

Voir cette section Wikipedia pour les détails: Conversion des couleurs en niveaux de gris

Je pense que vous souhaitez utiliser la formule pour Csrgb.
Essayez-le et voyez s'il correspond aux résultats que vous attendez.

Fondamentalement, vous ferez ceci:

  1. Prenez R, G, B couleur (chacune dans [0,1] gamme)
    • S'ils sont dans la plage 0..255 à la place, divisez simplement par 255.0
  2. Calculer Clinear = 0.2126 R + 0.7152 G + 0.0722 B
    • Il s'agit probablement de la transformation linéaire que vous appliquiez auparavant
  3. Calculer Csrgb selon sa formule, basée sur Clinear
    • Il s'agit de la pièce de correction gamma non linéaire qui vous manquait
    • Découvrez cette intrigue WolframAlpha
    • Csrgb = 12.92 Clinear quand Clinear <= 0.0031308
    • Csrgb = 1.055 Clinear1/2.4 - 0.055 quand Clinear > 0.0031308
24
Timothy Shields

Pour faire la remarque de Harold sur le "plan Y": les JPEG couleur standard sont encodés en utilisant l'espace colorimétrique YCbCr , où Y est la composante de luminance (c'est-à-dire la luminosité) et Cb et Cr sont la différence de bleu et le rouge- différences de chrominance. Donc, une façon de transformer un JPEG couleur en un niveau de gris est de simplement supprimer les composants Cb et Cr.

Il existe un utilitaire appelé jpegtran qui peut le faire sans perte, en utilisant le -grayscale option. (La partie sans perte n'aurait vraiment d'importance que si vous vouliez vous retrouver avec un JPEG et non un PGM, pour éviter perte de génération .) Dans tous les cas, ce serait probablement le moyen le plus rapide de faire cette transformation, car il ne décode même pas l'image en pixels, encore moins faire des calculs sur chacun.

4
Robert Fleming

ALGORITHME SIMPLE POUR CONVERTIR UNE IMAGE RVB EN ÉCHELLE DE GRIS DANS LE PYTHON OPENCV!

J'ai utilisé des commentaires pour que le code soit explicite, mais il fonctionne rapidement.

import cv2
import numpy as np
img1 = cv2.imread('opencvlogo.png')
row,col,ch = img1.shape
g = [ ]  #the list in which we will stuff single grayscale pixel value inplace of 3 RBG values
#this function converts each RGB pixel value into single Grayscale pixel value and appends that value to list 'g'
def rgb2gray(Img):
    global g
    row,col,CHANNEL = Img.shape
    for i in range(row) :
        for j in range(col):
        a =      (   Img[i,j,0]*0.07  +  Img[i,j,1]*0.72 +    Img[i,j,2] *0.21   ) #the algorithm i used id , G =  B*0.07 + G*0.72 + R* 0.21
                                                                                   #I found it online
        g.append(a)
rgb2gray(img1)  #convert the img1 into grayscale
gr = np.array(g)  #convert the list 'g' containing grayscale pixel values into numpy array
cv2.imwrite("test1.png" , gr.reshape(row,col)) #save the image file as test1.jpg

J'ai donc utilisé ce fichier image ... enter image description here

Mon programme a généré le fichier suivant en niveaux de gris.

enter image description here

1
bad programmer

En théorie, avec quelques pixels (3, dans ce cas), vous pouvez déterminer ce que fait leur algorithme. Choisissez simplement vos trois pixels (p1, p2, p3), leur valeur RVB et leur valeur de gris PGM, et vous avez:

RedConstant * p1.redValue + GreenConstant * p1.greenValue + BlueConstant * p1.blueValue = p1.grayValue

RedConstant * p2.redValue + GreenConstant * p2.greenValue + BlueConstant * p2.blueValue = p2.grayValue

RedConstant * p3.redValue + GreenConstant * p3.greenValue + BlueConstant * p3.blueValue = p3.grayValue.

Ensuite, résolvez ce problème (recherchez "solveur d'équations" ou quelque chose) et voyez quelles sont les constantes qu'ils utilisent.

1
Fabinout

Convertit un seul pixel d'entrée dans le RGB ColorModel par défaut en un seul pixel gris.

/* Convertation function 
 * @param x    the horizontal pixel coordinate
 * @param y    the vertical pixel coordinate
 * @param rgb  the integer pixel representation in the default RGB color model
 * @return a gray pixel in the default RGB color model.*/

    public int filterRGB(int x, int y, int rgb) {
    // Find the average of red, green, and blue.
    float avg = (((rgb >> 16) & 0xff) / 255f +
                 ((rgb >>  8) & 0xff) / 255f +
                  (rgb        & 0xff) / 255f) / 3;
    // Pull out the alpha channel.
    float alpha = (((rgb >> 24) & 0xff) / 255f);

    // Calculate the average.
    // Formula: Math.min(1.0f, (1f - avg) / (100.0f / 35.0f) + avg);
    // The following formula uses less operations and hence is faster.
    avg = Math.min(1.0f, 0.35f + 0.65f * avg);
    // Convert back into RGB.
   return (int) (alpha * 255f) << 24 |
          (int) (avg   * 255f) << 16 |
          (int) (avg   * 255f) << 8  |
          (int) (avg   * 255f);
}
0
Tomka Koliada