Pergunta

Input A image is a full RGB image, Output B image is a the same image but with "adjusted" R values

I need to rescale the RGB value to be between 128 and 255, so that minor values than 128 are scaled to an upper value.

RMAX = 127

img = cv2.imread(filename)         # load img
blue, green, red = cv2.split(img)  # get single color

red = red*RMAX/255+128             # scale the color as I need 

but this keep getting a wrong value:

if red value is 255 = 255*127/255+128 should output 255 but return 128

Why this happen?

EDIT:

The color values don't need to be recalculated every time, Would it be better to prepare an array at the start with the range of values, then replace the current value with the one from the array?

ValuesForRed = [0]*255

for i in range(0,255):
    ValuesForRed[i]=i*127 / 255 + 128

how to replace the values in the array is now the problem...

should replace the corresponding value with the corresponding index

i.e. red[45]= 0 
     ValuesForRed[0] = 128
     red[45]= 128

started new question at Python Opencv cv2.LUT() how to use

Foi útil?

Solução

This happens because red is unsigned char, which is a number in 0 to 255 range. However, you expect red to behave like integer.

So given that

red = 255
red = red*127/255 + 128

When the program multiplies red*127 the result will overflow because its value will be greater than 255, and so the answer will be 0 (because 255*127 modulo 255 = 0). Hence you get red = red*127/255 + 128 = (255*127 modulo 255) / 255 + 128 = 0 /255 + 128 = 128

To fix this, you can cast red to float when you do arithmetic operations on it, for example:

red = (float)red * 127 / 255

Edit As pointed out by William red is a cv::Mat of type CV_8U. You can convert the image to CV_32F type for calculations and then convert it back. For example (this is C++ code):

 Mat red_float;   
 red.convertTo(red_float,CV_32F);
 red_float = red_float*RMAX/255+128;
 red_float.convertTo(red,CV_8U);

Outras dicas

The other question that OP has is "how best to solve this problem?". This is how I would approach it. This is C++ code but you should be able to translate it to Python easily. This approach is fast and there is no need to convert matrices to CV_32F type.

  • Split input image into channels

    Mat input_image; //input image
    vector<Mat> split_image(3);
    split(input_image, split_image);
    Mat red = split_image[2];
    
  • Obtain mask_red, such that a location in mask_red is set to 255 if the corresponding location in red is between 129 and 255 (inclusive bounds), otherwise it is set to 0. This can be achieved with inRange() function.

    Mat mask_red;
    inRange(red, Scalar(129), Scalar(255), mask_red);
    
  • Now apply setTo() function to red to set all masked pixels to 255.

    red.setTo(Scalar(255), mask_red);
    
  • Merge the channels to form the final image.

    Mat output_image;   // output image
    merge(split_image, output_image);
    
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top