问题
I'm trying to write a converters algorithm that takes a JPEG image and returns its PGM (Portable Gray Map) version. The problem is that I can't understand how the "official" JPG->PGM convertitors work in terms of what value to assign to the final pixel (i guess, 0->255) starting from the classic RGB format.
At the beginning, I used this formula (it's the same used by OpenCV's CV_RGB2GRAY conversion):
0.30*R + 0.59*G + 0.11*B = val
I wrote a simple code to test my results: it takes a color image and its PGM version (already converted using GIMP). Then it converts the color image using the previous formula. The goal is to have a grayscale image that is pixel-to-pixel equal to the PGM input.
At this point, it does not return the same values. Can you help me?
回答1:
The problem is that I can't understand how the "official" JPG->PGM convertitors work in terms of what value to assign to the final pixel (i guess, 0->255) starting from the classic RGB format.
There is likely a gamma adjustment in the conversion those "official" tools are using.
That is, it is not just a linear transform.
See this Wikipedia section for the details: Converting color to grayscale
I believe you want to use the formula for Csrgb
.
Try it out and see if it matches the results you're expecting.
Basically, you'll do this:
- Take
R, G, B
color (each in[0,1]
range)- If they're in the range
0..255
instead, simply divide by255.0
- If they're in the range
- Compute
Clinear = 0.2126 R + 0.7152 G + 0.0722 B
- This is likely the linear transform you were applying before
- Compute
Csrgb
according to it's formula, based onClinear
- This is the nonlinear gamma correction piece you were missing
- Check out this WolframAlpha plot
Csrgb = 12.92 Clinear
whenClinear <= 0.0031308
Csrgb = 1.055 Clinear1/2.4 - 0.055
whenClinear > 0.0031308
回答2:
To harold's point about the "Y plane": standard color JPEGs are encoded using the YCbCr colorspace, where Y is the luminance component (i.e. the brightness) and Cb and Cr are the blue-difference and red-difference chroma components. So one way of turning a color JPEG into a grayscale one is to simply drop the Cb and Cr components.
There is a utility called jpegtran
than can do this losslessly, using the -grayscale
option. (The lossless part would really only matter if you wanted to end up with a JPEG and not PGM, to avoid generation loss.) In any case, this would probably be the fastest way to do this transformation, because it doesn't even decode the image into pixels, much less do math on each one.
回答3:
In theory, with a few pixels (3, in this case), you can determine what their algorithm is doing. Juste pick your three pixel (p1, p2, p3), their RGB value and their PGM gray value, and you have:
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.
Then solve this problem (look up "equation solver" or something) and see what are the constants they use.
回答4:
SIMPLE ALGORITHM TO CONVERT RGB IMAGE TO GRAYSCALE IN OPENCV PYTHON!
I used comments so code is self-explanatory.But it works swiftly.
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
SO I used this image file ...
My program generated following Grayscale file ..
回答5:
Converts a single input pixel in the default RGB ColorModel to a single gray pixel.
/* 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);
}
回答6:
Average method is the most simple one. You just have to take the average of three colors. Since its an RGB image, so it means that you have add r with g with b and then divide it by 3 to get your desired grayscale image.
Its done in this way.
Grayscale = (R + G + B / 3)
If you have an color image like the image shown above and you want to convert it into grayscale using average method.
来源:https://stackoverflow.com/questions/17615963/standard-rgb-to-grayscale-conversion