简体   繁体   English

OpenCV:着色失败

[英]OpenCV: Colorization failure

I am reading in an image and I would like to color in all non-zero pixels to red. 我正在读取图像,并且希望将所有非零像素的颜色都变为红色。 In addition, the background only consists of black. 此外,背景由黑色组成。 The code I wrote to try and do this is shown below: 我编写的尝试执行的代码如下所示:

import numpy as np
import cv2

second=cv2.imread('second.png') # read the picture

for i in range(second.shape[0]):
   for j in range(second.shape[1]):
       if second[i,j,0]!=0 and second[i,j,1]!=0 and second[i,j,2]!=0:# if it is not black pixel
           second[i,j,0]=0
           second[i,j,1]=0
           second[i,j,2]=255 # color it in red
cv2.imwrite('result.png',second) # save the colored picture

Here is the image second.png : 这是图片second.png

在此处输入图片说明

Here is the colored image result.png : 这是彩色图像result.png

在此处输入图片说明

How come some of the pixels aren't colored in as red? 为何有些像素没有被着色为红色? Note that when I print the colour pixel values of those locations in second.png that were not red in result.png , I see that they aren't black. 需要注意的是,当我打印在这些位置的颜色像素值second.png对于未在红result.png ,我看他们是不是黑色的。

Does anyone know why this may be? 有谁知道为什么会这样吗?

You should use or in your condition, such that all pixels that are not black are substituted: 您应使用or在您的条件下使用,以替换所有非黑色的像素:

import numpy as np
import cv2

second=cv2.imread('second.png') # read the picture

for i in range(second.shape[0]):
   for j in range(second.shape[1]):
       if second[i,j,0]!=0 or second[i,j,1]!=0 or second[i,j,2]!=0:# if it is not black pixel
           second[i,j,0]=0
           second[i,j,1]=0
           second[i,j,2]=255 # color it in red
cv2.imwrite('result.png',second) # save the colored picture

Alternatively, you could write if not(second[i,j,0]==0 and second[i,j,1]==0 and second[i,j,2]==0): as the condition, which is equivalent. 或者,您可以写if not(second[i,j,0]==0 and second[i,j,1]==0 and second[i,j,2]==0):作为条件,是等效的。

You can use cv::split and cv::merge if you wont to leave only read channel. 如果您不想只留下读通道,则可以使用cv::splitcv::merge Here is C++ example: 这是C ++示例:

#include <opencv2/opencv.hpp>


int main(int argc, char *argv[])
{
    cv::Mat src = cv::imread("second.png");
    cv::Mat b_g_r[3];
    cv::split(src, b_g_r);
    b_g_r[0] = cv::Mat::zeros(src.rows, src.cols, CV_8UC1); //blue to zeros
    b_g_r[1] = cv::Mat::zeros(src.rows, src.cols, CV_8UC1); //green to zeros
    cv::merge(b_g_r, 3, src);
    cv::imshow("Red", src);
    cv::waitKey();
    return 0;
}

And result: 结果:

The accepted answer by David Zwicker is certainly the way to go. David Zwicker接受的答案当然是正确的方法。 However, I would like to suggest something, and not use for loops with numpy arrays. 但是,我想提出一些建议,而不是 for numpy数组的循环。 I would suggest using a vectorized solution instead as you will most definitely get a boost in performance. 我建议您使用向量化解决方案,因为您绝对可以提高性能。 To me, this is the way numpy was meant to be used. 对我来说,这就是使用numpy的方式。

What I would do is split up the image into separate channels with numpy.split , then check each channel independently. 我要做的是使用numpy.split将图像分成单独的通道,然后独立检查每个通道。 We allocate a mask of the same size as one of the channels, and for each location in the image, if any of the channels is non-zero, we would mark this location to be True . 我们分配一个与通道之一大小相同的蒙版,并且对于图像中的每个位置,如果任何一个通道都不为零,则将该位置标记为True The result of this operation would be a mask where True denotes a non-zero pixel, and False otherwise. 此操作的结果将是一个掩码,其中True表示非零像素,否则为False You can use numpy.logical_or , but the standard syntax only accepts two inputs. 您可以使用numpy.logical_or ,但是标准语法仅接受两个输入。 If you want to use this over multiple inputs (ie greater than 2), you need to use the reduce idiom. 如果要在多个输入(即大于2)上使用它,则需要使用reduce惯用语。

Once you're done finding this mask, use numpy.nonzero to determine the locations in the mask that are non-zero or True , and create an output image which is initially all zeroes, then you set the red channel to 255 corresponding to these non-zero locations. 找到该蒙版之后,请使用numpy.nonzero确定蒙版中非零或True ,并创建一个最初为全零的输出图像,然后将红色通道设置为255,以与这些对应非零位置。

Or in other words: 换句话说:

import numpy as np
import cv2

img = cv2.imread('second.png') # read in image

# Look at each channel independently and see if there are any non-zero pixels
# and merge them together to create a mask
mask = np.logical_or.reduce(np.split(img, 3, axis=2))

# Find those locations in the mask that are non-zero
(rows, cols, _) = np.nonzero(mask)

# Create a blank image, then set the red channel to 255 for those non-zero locations
out = np.zeros(img.shape).astype('uint8')
out[rows,cols,2] = 255

# Show image, wait for key, then close window after
cv2.imshow('Red', out)
cv2.waitKey(0)
cv2.destroyAllWindows()

We get this: 我们得到这个:

在此处输入图片说明

It's totally up to you on what you want to do, but the above (to me) is more Pythonic. 完全由您决定要执行的操作,但是(对我来说)以上内容更像Python。 Use whatever you're most comfortable with! 使用最舒适的东西!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM