简体   繁体   中英

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 :

在此处输入图片说明

Here is the colored image 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.

Does anyone know why this may be?

You should use or in your condition, such that all pixels that are not black are substituted:

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.

You can use cv::split and cv::merge if you wont to leave only read channel. Here is C++ example:

#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. However, I would like to suggest something, and not use for loops with numpy arrays. 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.

What I would do is split up the image into separate channels with numpy.split , then check each channel independently. 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 . The result of this operation would be a mask where True denotes a non-zero pixel, and False otherwise. You can use numpy.logical_or , but the standard syntax only accepts two inputs. If you want to use this over multiple inputs (ie greater than 2), you need to use the reduce idiom.

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.

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. Use whatever you're most comfortable with!

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.

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