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
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);
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);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.