[英]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::split
和cv::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.