在Matlab中仅将黑色转换为白色

Léo*_* 준영 8 rgb matlab image colors image-processing

我知道这个关于同时将黑色转换为白色和白色转换为黑色的线索.我想只将黑色转换为白色.我知道这个线程是关于这样做我要问的但是我不明白出了什么问题.

图片

在此输入图像描述

rgbImage = imread('ecg.png');
grayImage = rgb2gray(rgbImage); % for non-indexed images
level = graythresh(grayImage); % threshold for converting image to binary, 
binaryImage = im2bw(grayImage, level); 
% Extract the individual red, green, and blue color channels.
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
% Make the black parts pure red.
redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 0;
blueChannel(~binaryImage) = 0;
% Now recombine to form the output image.
rgbImageOut = cat(3, redChannel, greenChannel, blueChannel);
imshow(rgbImageOut);
Run Code Online (Sandbox Code Playgroud)

这使

在此输入图像描述

红色通道似乎有些不对劲.黑色只是RGB中的(0,0,0),因此它的去除应该意味着将每个(0,0,0)像素变为白色(255,255,255).用这个想法

redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 255;
blueChannel(~binaryImage) = 255;
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

所以我一定在Matlab中误解了一些东西.蓝色不应该有任何黑色.所以这最后一张图片很奇怪.

你怎么能只把黑色变成白色? 我想保持心电图的蓝色.

ray*_*ica 7

如果我理解正确,您需要在删除文本和轴的同时提取蓝色ECG图.最好的方法是检查图像的HSV颜色空间.HSV色彩空间非常适合辨别色彩,就像人类一样.我们可以清楚地看到图像中有两种不同的颜色.

我们可以使用图像将图像转换为HSV rgb2hsv,我们可以分别检查这些组件.色调分量表示像素的主色,饱和度表示像素中的纯度或白光多少,并且该值表示像素的强度或强度.

尝试将每个频道可视化:

im = imread('http://i.stack.imgur.com/cFOSp.png'); %// Read in your image
hsv = rgb2hsv(im);
figure;
subplot(1,3,1); imshow(hsv(:,:,1)); title('Hue');
subplot(1,3,2); imshow(hsv(:,:,2)); title('Saturation');
subplot(1,3,3); imshow(hsv(:,:,3)); title('Value');
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

嗯......很好的色调和饱和度对我们没有帮助.它告诉我们主导颜色和饱和度是相同的...但是它们与众不同的是价值.如果你看一下右边的图像,我们可以通过颜色本身的强度来区分它们.所以它告诉我们的是,"黑色"像素实际上是蓝色的,但几乎没有与之相关的强度.

我们实际上可以利用这个优势.值大于特定值的任何像素都是我们想要保留的值.

尝试设置一个阈值...类似于0.75.MATLAB的HSV值动态范围来自[0-1],所以:

mask = hsv(:,:,3) > 0.75;
Run Code Online (Sandbox Code Playgroud)

当我们对值组件进行阈值处理时,这就是我们得到的:

在此输入图像描述

显然有一些量化噪声......特别是在轴和字体周围.我接下来要做的是进行形态侵蚀,这样我就可以消除每个数字和轴周围的量化噪声.我要把面具做得有点大,以确保我消除这种噪音.使用图像处理工具箱:

se = strel('square', 5);
mask_erode = imerode(mask, se);
Run Code Online (Sandbox Code Playgroud)

我们得到这个:

在此输入图像描述

太棒了,所以我现在要做的就是复制原始图像,然后在最终图像中将我从上面导出的蒙版(上图)中的任何黑色像素设置为白色.所有其他像素应保持完整.这样,我们可以删除图像中看到的任何文本和轴:

im_final = im;
mask_final = repmat(mask_erode, [1 1 3]);
im_final(~mask_final) = 255;
Run Code Online (Sandbox Code Playgroud)

我需要在第三维中复制蒙版,因为这是一个彩色图像,我需要在相同的空间位置同时将每个通道设置为255.

当我这样做时,这就是我得到的:

在此输入图像描述

现在您将注意到图中存在间隙....由于量化噪声而预期.我们可以通过将此图像转换为灰度并对图像进行阈值处理,然后通过形态膨胀将边缘填充在一起来做更进一步的操作.这是安全的,因为我们已经消除了轴和文本.然后我们可以使用它作为掩码来索引原始图像以获得我们的最终图形.

像这样的东西:

im2 = rgb2gray(im_final);
thresh = im2 < 200;
se = strel('line', 10, 90);
im_dilate = imdilate(thresh, se);
mask2 = repmat(im_dilate, [1 1 3]);
im_final_final = 255*ones(size(im), class(im));
im_final_final(mask2) = im(mask2);
Run Code Online (Sandbox Code Playgroud)

在将其转换为灰度后,我对没有文本和轴的前一个图像进行阈值处理,然后使用90度的线结构元素执行扩张,以便连接最初断开连接的那些线.这个阈值化的图像将包含我们最终需要从原始图像中采样的像素,以便我们可以获得所需的图形数据.

然后我拿这个面具,复制它,制作一个完全白色的图像,然后从原始图像中取样,并将原始图像中我们想要的位置放在白色图像中.

这是我们的最终形象:

在此输入图像描述

非常好!我不得不做所有的图像处理,因为你的图像开始时基本上都有量化噪声,因此完全获得图形会有点困难.Ander Biguri在他的回答中更详细地解释了颜色量化噪声,因此请查看他的帖子了解更多细节.

但是,作为定性测量,我们可以从原始图像中减去此图像,并查看剩余的内容:

imshow(rgb2gray(abs(double(im) - double(im_final_final))));
Run Code Online (Sandbox Code Playgroud)

我们得到:

在此输入图像描述

因此看起来轴和文本被删除很好,但是图中有一些痕迹我们没有从原始图像中捕获并且这是有意义的.这一切都与您想要选择的正确阈值有关,以便获取图形数据.在图的开头附近有一些麻烦点,这可能是由于我所做的形态处理.你提供的这个图像对量化噪声非常棘手,因此要获得完美的结果将非常困难.此外,遗憾的是,这些阈值都是启发式的,因此请使用阈值,直到获得与您同意的内容为止.

祝好运!

  • 我将完成编辑我的问题,因为它看起来像(我非常兴奋)我的答案比惊人的rayryeng做得好一点(OMGOMGOMG,这不常见!).看看@Masi (2认同)
  • @AnderBiguri - lmao.我欢迎不时被证明是错误的.请让我看看你的结果:) (2认同)
  • @rayryeng抱歉有点长时间张贴他们.他们在那里! (2认同)

And*_*uri 5

有什么问题?

您想要检测图像的所有黑色部分,但它们并不是真正的黑色

例:

在此输入图像描述

你的想法(或你的代码):

您首先将图像二值化,选择与非像素相对的像素.简而言之,你做到:if pixel>level; pixel is something

因此,你有一个小的误解!当你写作

% Make the black parts pure red.
Run Code Online (Sandbox Code Playgroud)

它应该读

% Make every pixel that is something (not background) pure red.
Run Code Online (Sandbox Code Playgroud)

因此,当你这样做

redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 255;
blueChannel(~binaryImage) = 255;
Run Code Online (Sandbox Code Playgroud)

你在做

% Make every pixel that is something (not background) white 
% (or what it is the same in this case, delete them).
Run Code Online (Sandbox Code Playgroud)

因此,你应该得到一个完全白色的图像.图像不是完全白色的,因为level在图像大约为0.6的情况下,有些像素被标记为"不是某物,是背景的一部分" .

人们可以想到的解决方案是手动将水平设置为0.05或类似,因此在灰色到二进制的保持中仅选择黑色像素.但是这不会100%有效,正如你所看到的,数字有一些非常"非黑"的值.


我该如何解决这个问题:

我会尝试找到你想要的颜色,从图像中提取该颜色,然后删除异常值.

使用HSV提取蓝色(我相信我在其他地方回答了你如何使用HSV).

rgbImage = imread('ecg.png');
hsvImage=rgb2hsv(rgbImage);
I=rgbImage;
R=I(:,:,1);
G=I(:,:,2);
B=I(:,:,3);
th=0.1;
R((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
G((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
B((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
I2= cat(3, R, G, B);

imshow(I2)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

一旦到了这里,我们希望得到最大的蓝色部分,这将是我们的信号.因此,最好的方法似乎是首先将所有蓝色像素的图像二值化

% Binarize image, getting all the pixels that are "blue"
bw=im2bw(rgb2gray(I2),0.9999);
Run Code Online (Sandbox Code Playgroud)

然后使用bwlabel,标记所有独立像素"孤岛".

% Label each "blob"
lbl=bwlabel(~bw);
Run Code Online (Sandbox Code Playgroud)

最重复的标签将是信号.所以我们找到它并使用该标签将背景与信号分开.

% Find the blob with the highes amount of data. That  will be your signal.
r=histc(lbl(:),1:max(lbl(:)));
[~,idxmax]=max(r);
% Profit!
signal=rgbImage;
signal(repmat((lbl~=idxmax),[1 1 3]))=255;
background=rgbImage;
background(repmat((lbl==idxmax),[1 1 3]))=255;
Run Code Online (Sandbox Code Playgroud)

这里有一个信号,背景和差异的图(使用与@rayryang相同的等式)

在此输入图像描述

  • 非常好.几乎相同的方法我差点大声笑.+1. (2认同)