【问题标题】:To convert only black color to white in Matlab在 Matlab 中仅将黑色转换为白色
【发布时间】:2015-06-30 06:14:22
【问题描述】:

我知道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 中的某些内容。蓝色不应有任何黑色。所以最后这张图很奇怪。

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

【问题讨论】:

    标签: image matlab image-processing colors rgb


    【解决方案1】:

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

    我们可以使用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');
    

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

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

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

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

    当我们对值组件设置阈值时,我们得到的是:

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

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

    我们得到这个:

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

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

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

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

    这是我们的最终图像:

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

    但是,作为一种定性测量,我们可以从原始图像中减去该图像,看看剩下的是什么:

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

    我们得到:

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

    祝你好运!

    【讨论】:

    • @Masi - 但是,如果您想确定 0.600.75 之间的掩码中有多少像素不同,只需使用该数量对两个图像进行阈值处理并将它们存储在单独的图像中...称为I1I2,然后执行abs(nnz(I1) - nnz(I2)) 以确定两个图像之间有多少像素不同。从那里您可以确定经历了多少百分比变化。
    • @Masi - 哎呀。抱歉等一下
    • 我将完成我的问题的编辑,因为看起来(我非常兴奋)我的回答比令人惊叹的 rayryeng 所做的要好一点(OMGOMGOMGOMG,这不常见!)。看看@Masi
    • @AnderBiguri - lmao。我欢迎不时被证明是错误的。请让我看看你的结果:)
    • @rayryeng 抱歉花了很长时间发布它们。他们来了!
    【解决方案2】:

    有什么问题?

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

    例子:

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

    您首先对图像进行二值化处理,选择存在的像素与不存在的像素。简而言之,您可以:if pixel&gt;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).
    

    因此,您应该得到一张全白的图像。图像不是完全白色的,因为在您的图像大约为 0.6 的情况下,有一些像素被level 的值标记为“不是某物,是背景的一部分”。

    可以想到的一种解决方案是将级别手动设置为 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)
    

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

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

    然后使用bwlabel,标记所有独立像素“岛”。

    % 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 相同的方程)

    【讨论】:

    • 非常好。几乎与我采取的方法几乎相同,哈哈。 +1。
    • 这听起来不错一个可以想到的解决方案是手动将级别设置为 0.05 或类似值,因此在灰度到二进制阈值中只会选择黑色像素。 你平均值为二进制阈值 0.60 和级别 0.05。如果能够使用阈值 0.60 和级别 0.05 来近似估计丢失信号的不确定性或数量,那就太好了。并将其与阈值 0.75 与 0.05 水平进行比较。我认为0.05级别是一个不错的选择。我认为可变参数是阈值。
    • @Masi Level==gray2bw 阈值在这种情况下。但是,请查看我更新的答案以查看从图中提取信号的方法
    • @AnderBiguri 是的,我做到了。我还计算了中心的像素,但没有找到。我数了数图片中没有文字的所有白色像素。
    • 这是一个索引问题。每当需要白色像素时,您需要将 3 通道 (RGB) 设置为 255,因此设置为 3。“如何读取整行?”是什么意思?方法?。我确实选择了不是最大的斑点并将它们的颜色设置为白色。 @Masi
    【解决方案3】:

    这是@rayryeng's solution 的变体,用于提取蓝色信号:

    %// 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)
    

    为了获得更好的视图,这是覆盖在原始图像顶部的检测到的蒙版(我正在使用来自 File Exchange 的 imoverlay 函数):

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

    【讨论】:

    • 我浏览了一组心电图信号及其时频对应关系,其中信号的强度也通过颜色可视化。此方法在此 TF 空间中中断。但是,它似乎在统一的 ECG 信号中效果很好。稍后我将尝试提供有关这些特殊情况的一些数据。我现在正在测试这种方法是否适用于 ECG 的所有变体。只要颜色编码是统一的,就应该这样做。
    【解决方案4】:

    这是一个代码:

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

    【讨论】:

    • 如果阈值为 240,您能否估算出丢失了多少数据?挑战在于通过选择阈值找到足够好的数据。
    • 第240张图就是这张dropbox.com/s/pxl99xd8zd64xxt/…
    • 丢失数据是什么意思?改变了蓝色图形的像素?
    • 我用蓝色 250 的阈值尝试了这个,红色和绿色通道被删除了。图表的任何像素都没有改变。不会丢失数据。
    • 你是对的。我没有比较图表的这一部分。我只比较了图像部分(32:438,48:565,:)。在本节中没有区别。严格来说,图表没有改变,因为此时还没有图表。
    猜你喜欢
    • 1970-01-01
    • 2013-09-17
    • 2018-12-23
    • 1970-01-01
    • 2019-12-13
    • 2015-04-07
    • 1970-01-01
    • 2013-08-29
    相关资源
    最近更新 更多