OpenCV RGB单通道颜色调整

5

输入的A图像是一个完整的RGB图像, 输出的B图像是同一张图片,但是“调整”了R值。

我需要重新调整RGB值,使其在128到255之间,这样小于128的值就会被缩放到一个更高的值。

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 

但这个值一直是错误的:

如果红色值为255 = 255*127/255+128,应该输出255,但返回128

为什么会发生这种情况?

编辑:

颜色值不需要每次重新计算,最好在开始时准备一个具有范围值的数组,然后用数组中的值替换当前值。

ValuesForRed = [0]*255

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

如何替换数组中的值是现在的问题...

应该用相应的索引替换相应的值

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

我在Python Opencv cv2.LUT()如何使用的问题上提出了新的疑问。


您可以使用我第二个答案的建议。它展示了如何在C++中逐步解决问题的方法。在Python中的方法也类似。主要思路是使用inRange()函数(在Python OpenCV中可用)来获取图像的掩模,该掩模指定像素的值位于129到255之间(包括边界)。有关详细信息,请参阅第二个答案。 - Alexey
2个回答

5
这是因为 red 是一个 unsigned char,其数值范围在 0 到 255 之间。然而,您要求它的行为像整数一样。
因此,考虑到
red = 255
red = red*127/255 + 128

当程序将红色值乘以127时,结果会溢出,因为其值将大于255,所以答案将是0(因为255*127模255=0)。 因此,您可以得到red = red * 127/255 + 128 =(255 * 127模255)/ 255 + 128 = 0/255 + 128 = 128
要解决这个问题,您可以在对其进行算术运算时将red转换为浮点数,例如:
red = (float)red * 127 / 255

编辑 正如William指出的那样,red是一个类型为CV_8Ucv::Mat。你可以将图像转换为CV_32F类型进行计算,然后再将其转换回来。例如(这是C++代码):

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

1
同意。此外,可以使用类型为CV_32FC3的辅助cv :: Mat进行计算,然后使用convertTo(,CV_8UC3)转换为uchar。 - LovaBill
我正在使用Python 2.7,我尝试了int(red * 127 / 255 + 128),但是出现了TypeError: only length-1 arrays can be converted to Python scalars的错误。所以我尝试了abs(red * 127 / 255 + 128),但它仍然没有进行转换,仍然得到了128。 - user2239318
1
@user2239318 red是一个矩阵。因此,您需要按照答案的第二部分所述(对于C ++)将矩阵转换为CV_32F类型。由于您正在使用Python,这个答案可能会有所帮助。 - Alexey
红色= np.int16(红) 红色= 红色* 127 / 255 + 128 计算是正确的,但当我合并新颜色时,出现了以下错误:cv2.error:/build/opencv-Ai8DTy/opencv-2.4.6.1+dfsg/modules/core/src/convert.cpp:286: error:(-215) mv[i].size == mv[0].size && mv[i].depth() == depth in function merge - user2239318
@user2239318 你的问题是“为什么会发生这种情况?”。我已经回答了。请告诉我更详细地您想要实现什么,或者编辑您的问题,以便我可以更好地帮助您。您也可以将其作为一个新问题发布。 - Alexey

2
另一个问题是OP问的“如何解决这个问题?”。这是我的解决方案。以下是C++代码,但您应该能够轻松将其翻译为Python。此方法快速且无需将矩阵转换为CV_32F类型。
  • 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);
    

实际上我需要进行比例缩放,inRange似乎会在范围内返回255,类似于如果验证成功则返回true,而不是按比例缩放,如0:128,3:129等... - user2239318

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接