OpenCV:着色失败
OpenCV: Colorization failure
我正在读入一幅图像,我想将所有非零像素着色为红色。此外,背景仅由黑色组成。我为尝试执行此操作而编写的代码如下所示:
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
这是图片second.png:
这是彩色图片result.png:
为什么有些像素没有涂成红色?请注意,当我打印 second.png
中那些在 result.png
中不是红色的位置的颜色像素值时,我发现它们不是黑色。
有人知道这是为什么吗?
您应该在您的条件下使用 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
或者,你可以写if not(second[i,j,0]==0 and second[i,j,1]==0 and second[i,j,2]==0):
作为条件,这是等价的。
如果您不想离开只读频道,您可以使用 cv::split
和 cv::merge
。
这是 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;
}
结果:
David Zwicker 接受的答案当然是可行的方法。但是,我想提出一些建议,并且 not 将 for
循环与 numpy
数组一起使用。我建议改用矢量化解决方案,因为您肯定会获得性能提升。对我来说,这就是 numpy
的使用方式。
我会做的是用 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 (i.e. greater than 2), you need to use the reduce
成语将图像分成单独的通道。
找到这个掩码后,使用 numpy.nonzero
确定掩码中非零或 True
的位置,并创建一个最初全为零的输出图像,然后将红色通道设置为 255 对应于这些非零位置。
或者换句话说:
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()
我们得到这个:
这完全取决于你想做什么,但以上(对我来说)更像 Pythonic。使用您最喜欢的任何东西!
我正在读入一幅图像,我想将所有非零像素着色为红色。此外,背景仅由黑色组成。我为尝试执行此操作而编写的代码如下所示:
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
这是图片second.png:
这是彩色图片result.png:
为什么有些像素没有涂成红色?请注意,当我打印 second.png
中那些在 result.png
中不是红色的位置的颜色像素值时,我发现它们不是黑色。
有人知道这是为什么吗?
您应该在您的条件下使用 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
或者,你可以写if not(second[i,j,0]==0 and second[i,j,1]==0 and second[i,j,2]==0):
作为条件,这是等价的。
如果您不想离开只读频道,您可以使用 cv::split
和 cv::merge
。
这是 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;
}
结果:
David Zwicker 接受的答案当然是可行的方法。但是,我想提出一些建议,并且 not 将 for
循环与 numpy
数组一起使用。我建议改用矢量化解决方案,因为您肯定会获得性能提升。对我来说,这就是 numpy
的使用方式。
我会做的是用 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 (i.e. greater than 2), you need to use the reduce
成语将图像分成单独的通道。
找到这个掩码后,使用 numpy.nonzero
确定掩码中非零或 True
的位置,并创建一个最初全为零的输出图像,然后将红色通道设置为 255 对应于这些非零位置。
或者换句话说:
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()
我们得到这个:
这完全取决于你想做什么,但以上(对我来说)更像 Pythonic。使用您最喜欢的任何东西!