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

To convert only black color to white in Matlab

我知道 thread 关于同时将黑色转换为白色和将白色转换为黑色的方法。 我只想将黑色转换为白色。 我知道这个 thread 关于按照我的要求执行此操作,但我不明白哪里出了问题。

图片

代码

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);

给出

红色通道好像哪里出了问题。 黑色在 RGB 中只是 (0,0,0),所以它的移除应该意味着将每个 (0,0,0) 像素变成白色 (255,255,255)。 用

做这个想法
redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 255;
blueChannel(~binaryImage) = 255;

给予

所以我一定是误解了 Matlab 中的某些东西。蓝色不应有任何黑色。所以最后这张图很奇怪。

怎么才能把黑色变成白色呢? 我想保留心电图的蓝色。

这是一个代码:

rgbImage = imread('ecg.png');

redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);

black = ~redChannel&~greenChannel&~blueChannel;

redChannel(black) = 255;
greenChannel(black) = 255;
blueChannel(black) = 255;

rgbImageOut = cat(3, redChannel, greenChannel, blueChannel);

imshow(rgbImageOut);

black 是包含黑色像素的区域。这些像素在每个颜色通道中都设置为白色。

在您的代码中,您使用了阈值和灰度图像,因此您当然有更大的像素区域设置为白色。红色。在这段代码中,只有完全不包含红色、绿色和蓝色的像素才被设置为白色。

以下代码对每个颜色通道的阈值执行相同的操作:

rgbImage = imread('ecg.png');

redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);

black = (redChannel<150)&(greenChannel<150)&(blueChannel<150);

redChannel(black) = 255;
greenChannel(black) = 255;
blueChannel(black) = 255;

rgbImageOut = cat(3, redChannel, greenChannel, blueChannel);

imshow(rgbImageOut);

有什么问题吗?

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

示例:

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

您首先将图像二值化,选择是的像素与不是的像素。简而言之,您可以:if pixel>level; pixel is something

所以你这里有个小误会!当你写

% Make the black parts pure red.

应该是

% Make every pixel that is something (not background) pure red.

因此,当您这样做时

redChannel(~binaryImage) = 255;
greenChannel(~binaryImage) = 255;
blueChannel(~binaryImage) = 255;

你在做

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

因此你得到的应该是一个全白的图像。图像不是完全白色的,因为有一些像素被 level 的值标记为 "not something, part of the background",如果你的图像在 0.6 左右。

人们可以想到的一种解决方案是手动将级别设置为 0.05 或类似值,这样在灰色到二进制阈值处理中只会选择黑色像素。 但是 这不会 100% 有效,如您所见,这些数字有一些非常 "no-black" 的值。


我将如何尝试解决问题:

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

使用 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)

到达这里后,我们希望获得最大的蓝色部分,这将是我们的信号。因此,最好的方法似乎是首先对采用所有蓝色像素的图像进行二值化

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

然后使用bwlabel,标记所有独立像素"islands"。

% Label each "blob"
lbl=bwlabel(~bw);

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

% 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;

这里有一个包含信号、背景和差异的图(使用与@rayryang 使用的相同的方程式)

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

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

尝试想象每个通道在做:

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');

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

我们实际上可以利用这一优势。任何值高于某个值的像素都是我们要保留的值。

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

mask = hsv(:,:,3) > 0.75;

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

显然有一点量化噪音......尤其是在轴和字体周围。接下来我要做的是执行形态学 腐蚀 以便我可以消除每个数字和轴周围的量化噪声。我打算把它做大一点,以确保我消除了这种噪音。使用图像处理工具箱:

se = strel('square', 5);
mask_erode = imerode(mask, se);

我们得到这个:

太好了,所以我现在要做的是复制您的原始图像,然后从我导出的蒙版(上图)中设置 black 的任何像素在最终图像中变为白色。所有其他像素应保持不变。这样,我们就可以删除您图像中看到的任何文本和坐标轴:

im_final = im;
mask_final = repmat(mask_erode, [1 1 3]);
im_final(~mask_final) = 255;

我需要在三维中复制蒙版,因为这是一张彩色图像,我需要在相同的空间位置同时将每个通道设置为 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);

我在将它转换为灰度后,对我们得到的没有文本和坐标轴的先前图像进行阈值处理,然后我使用 line 90 度的结构元素进行膨胀为了连接那些最初断开的线路。这个阈值图像将包含我们最终需要从原始图像中采样的像素,以便我们可以获得我们需要的图形数据。

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

这是我们的最终图像:

非常好!我必须做所有的图像处理,因为你的图像基本上从一开始就有量化噪声,所以要完全获得图表会有点困难。 Ander Biguri 在他的回答中更详细地解释了颜色量化噪声,因此请务必查看他的 post 了解更多详细信息。

然而,作为一种定性测量,我们可以从原始图像中减去这张图像,看看还剩下什么:

imshow(rgb2gray(abs(double(im) - double(im_final_final))));

我们得到:

所以看起来轴和文本被很好地删除了,但是图中有一些我们没有从原始图像中捕捉到的痕迹,这是有道理的。这一切都与您想要 select 的适当阈值有关,以便获取图形数据。在图表的开头附近有一些问题点,这可能是由于我所做的形态学处理造成的。您提供的这张图像在量化噪声方面非常棘手,因此很难获得完美的结果。此外,不幸的是,这些阈值都是启发式的,因此请尝试调整阈值,直到获得与您一致的结果。

祝你好运!

这里是 的变体,用于提取蓝色信号:

%// retrieve picture
imgRGB = imread('http://i.stack.imgur.com/cFOSp.png');

%// detect axis lines and labels
imgHSV = rgb2hsv(imgRGB);
BW = (imgHSV(:,:,3) < 1);
BW = imclose(imclose(BW, strel('line',40,0)), strel('line',10,90));

%// clear those masked pixels by setting them to background white color
imgRGB2 = imgRGB;
imgRGB2(repmat(BW,[1 1 3])) = 255;

%// show extracted signal
imshow(imgRGB2)

为了获得更好的视图,这是覆盖在原始图像之上的检测到的蒙版(我正在使用文件交换中的 imoverlay 功能):

figure
imshow(imoverlay(imgRGB, BW, uint8([255,0,0])))