人眼很容易从其他颜色中辨别黑色。但是计算机呢?
我在普通A4纸上打印了一些色块。由于有三种墨水组成彩色图像,青色,品红色和黄色,我设置每个块的颜色C = 20%,C = 30%,C = 40%,C = 50%,其余两种颜色这是我的源图像的第一列。到目前为止,没有黑色( K 的CMYK)墨水应该打印。之后,我设置每个点的颜色K = 100%,其余颜色为0以打印黑点。
你可能觉得我的形象很奇怪而且可怕。实际上,图像被放大了30倍,并且可以清楚地看到墨水如何作弊我们的眼睛。色条妨碍我识别这些黑点(点打印为800 dpi的一个像素)。如果没有颜色背景,我习惯blur
并执行canny edge detector
来提取边缘。但是,在添加彩色背景时,由于条带的原因,grayscale
和edge detector
无法获得良好的效果。为了解决这些问题,我的眼睛会怎样做?
我决定检查源图像的亮度。我提到this article和公式:
亮度= sqrt(0.299 R * R + 0.587 G * G + 0.114 B * B)
亮度更接近人类的感知,并且在黄色背景下效果非常好,因为与青色和品红色相比,黄色的亮度最高。但如何使青色和洋红色条带尽可能明亮?预期的结果是所有条带都消失了。
更复杂的图片
C = 40%,M = 40%
C = 40%,Y = 40%
Y = 40%,M = 40%
C = 40%,Y = 40%亮度图像的FFT结果
任何人都可以给我一些提示来删除彩条吗?
@natan我试过FFT method你建议我,但我不幸在两个轴x和y都达到峰值。为了像你一样绘制频率,我将图像调整为正方形。
答案 0 :(得分:3)
我会将图像转换为HSV颜色空间,然后使用Value通道。这基本上分离了颜色和亮度信息。
这是50%的青色图像
然后你可以做一个简单的阈值来隔离点。
我只是很快就这样做了,我相信你可以获得更好的结果。也许在图像中找到轮廓,然后删除任何小面积的轮廓,以过滤任何剩余的噪音。
答案 1 :(得分:2)
在检查图像后,我认为稳健的阈值比任何事情都更简单。例如,看着C = 40%,M = 40%的照片,我首先将强度反转为黑色(信号)仅使用白色
im=(abs(255-im));
我们可以检查其RGB histograms using this:
hist(reshape(single(im),[],3),min(single(im(:))):max(single(im(:))));
colormap([1 0 0; 0 1 0; 0 0 1]);
所以我们看到对某些中等强度有很大的贡献,而现在是白色的“信号”大多分为更高的值。然后我应用了一个简单的阈值如下:
thr = @(d) (max([min(max(d,[],1)) min(max(d,[],2))])) ;
for n=1:size(im,3)
imt(:,:,n)=im(:,:,n).*uint8(im(:,:,n)>1.1*thr(im(:,:,n)));
end
imt=rgb2gray(imt);
并摆脱小于某些典型区域大小的物体
min_dot_area=20;
bw=bwareaopen(imt>0,min_dot_area);
imagesc(bw);
colormap(flipud(bone));
这是与原始图像一起的结果:
这个阈值的起源来自this code我写的是在嘈杂的背景中以二维峰值或斑点的形式假设稀疏信号。稀疏我的意思是没有堆积的山峰。在这种情况下,当在x或y轴上投影max(图像)时((max(im,[],1)
或(max(im,[],1)
,您可以很好地测量背景。这是因为您采用{{{{{{{ 1}}向量。
如果你想以不同的方式看待它,你可以看一下图像强度的直方图。背景应该是某种强度附近的某种正态分布,信号应该高于该强度,但出现次数要低得多。通过查找其中一个轴(x或y)的max(im)
,您可以发现最大噪声级别。
你会看到阈值在直方图中选择了那个点上面仍然有一些噪音,但是所有信号都高于它。这就是我将其调整为max(im)
的原因。最后,有许多更好的方法可以获得稳健的阈值,这是一种快速而肮脏的方式,在我看来已经足够了......
答案 2 :(得分:2)
感谢大家发布他的答案!经过一番搜索和尝试后,我还想出了一种自适应方法从彩色背景中提取这些黑点。似乎只考虑 亮度无法完美解决问题。因此, natan 计算和分析RGB直方图的方法更加稳健。不幸的是,我仍然无法获得一个强大的阈值来提取其他颜色样本中的黑点,因为当我们添加更深的颜色(例如Cyan> 60)或将两种颜色混合在一起时(例如Cyan = 50,事情变得越来越难以预测)洋红色= 50)。
有一天,我谷歌“提取颜色”,TinEye's color extraction和color thief激励我。它们都是非常酷的应用程序,前网站处理的图像正是我想要的。所以我决定自己实现类似的东西。我在这里使用的算法是 k-means clustering 。其他一些与搜索相关的关键词可能是color palette
,color quantation
和getting dominant color
。
我首先使用高斯滤镜来平滑图像。
GaussianBlur(img, img, Size(5, 5), 0, 0);
OpenCV具有kmeans功能,它为编码节省了大量时间。我修改了this code。
// Input data should be float32
Mat samples(img.rows * img.cols, 3, CV_32F);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
for (int z = 0; z < 3; z++) {
samples.at<float>(i + j * img.rows, z) = img.at<Vec3b>(i, j)[z];
}
}
}
// Select the number of clusters
int clusterCount = 4;
Mat labels;
int attempts = 1;
Mat centers;
kmeans(samples, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10, 0.1), attempts, KMEANS_PP_CENTERS, centers);
// Draw clustered result
Mat cluster(img.size(), img.type());
for (int i = 0; i < img.rows; i++) {
for(int j = 0; j < img.cols; j++) {
int cluster_idx = labels.at<int>(i + j * img.rows, 0);
cluster.at<Vec3b>(i, j)[0] = centers.at<float>(cluster_idx, 0);
cluster.at<Vec3b>(i, j)[1] = centers.at<float>(cluster_idx, 1);
cluster.at<Vec3b>(i, j)[2] = centers.at<float>(cluster_idx, 2);
}
}
imshow("clustered image", cluster);
// Check centers' RGB value
cout << centers;
聚类后,我将结果转换为灰度,找到最黑的颜色,这种颜色更可能是黑点的颜色。
// Find the minimum value
cvtColor(cluster, cluster, CV_RGB2GRAY);
Mat dot = Mat::zeros(img.size(), CV_8UC1);
cluster.copyTo(dot);
int minVal = (int)dot.at<uchar>(dot.cols / 2, dot.rows / 2);
for (int i = 0; i < dot.rows; i += 3) {
for (int j = 0; j < dot.cols; j += 3) {
if ((int)dot.at<uchar>(i, j) < minVal) {
minVal = (int)dot.at<uchar>(i, j);
}
}
}
inRange(dot, minVal - 5 , minVal + 5, dot);
imshow("dot", dot);
让我们测试两张图片。
(clusterCount = 4
)
(clusterCount = 5
)
k-means聚类的一个缺点是固定的clusterCount
不能应用于每个图像。对于较大的图像,聚类也不是那么快。这个问题让我很烦恼。我更好的实时性能(在iPhone上)的脏方法是裁剪1/16的图像并聚集较小的区域。然后将原始图像中的所有像素与每个聚类中心进行比较,并选择最接近“黑色”颜色的像素。我只是计算两种RGB颜色之间的欧氏距离。
答案 3 :(得分:0)
一种简单的方法是只对所有像素进行阈值处理。这是用伪代码表达的想法。
for each pixel in image
if brightness < THRESHOLD
pixel = BLACK
else
pixel = WHITE
或者如果你总是处理青色,品红色和黄色背景,那么你可能会用标准获得更好的结果
if pixel.r < THRESHOLD and pixel.g < THRESHOLD and pixel.b < THRESHOLD
这种方法只能为简单的图像提供良好的效果,除了黑点以外什么都不是。
您可以尝试使用THRESHOLD的值来为图像找到一个好的值。
答案 4 :(得分:0)
我建议转换为一些基于色度的色彩空间,如LCH,并调整亮度和色度的同时阈值。这是L&lt;的结果掩码。 50&amp; C&lt; 25为输入图像:
似乎您需要自适应阈值,因为不同的值最适合图像的不同区域。
您也可以使用HSV或HSL作为色彩空间,但它们在感知上比从实验室派生的LCH更不均匀。