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?
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:
R, G, B
couleur (chacune dans [0,1]
gamme)0..255
à la place, divisez simplement par 255.0
Clinear = 0.2126 R + 0.7152 G + 0.0722 B
Csrgb
selon sa formule, basée sur Clinear
Csrgb = 12.92 Clinear
quand Clinear <= 0.0031308
Csrgb = 1.055 Clinear1/2.4 - 0.055
quand Clinear > 0.0031308
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.
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 ...
Mon programme a généré le fichier suivant en niveaux de gris.
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.
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);
}