查找图像中的深紫色像素

Finding dark purple pixels in an image

我正在为我的自动化高等研究做研究。我已经完成了显微镜的自动化部分,但我需要 MATLAB 的帮助。此处显示了我想要细分的示例:

我需要从该图像中提取深紫色像素并仅在图中显示。这几乎就像基于颜色的分割,但我只想从整个图像中提取深紫色像素。

在这种情况下我会怎么做?

这里有一些可以帮助您入门的东西。让我们以颜色分割为主题,您只想提取深紫色的像素。在我们开始之前,我想向您指出 HSV colour space。 HSV 颜色 space 非常适合以人类最直观的方式表示颜色。我们倾向于通过主色来描述颜色,然后是颜色的褪色程度或纯度,以及颜色的亮暗程度等属性。主色由 Hue 表示,颜色的褪色程度或纯度由 Saturation 表示,颜色强度由 Value 表示,因此 Hue-Saturation-Value,或者HSV颜色space.

我们可以通过rgb2hsv对RGB图像进行变换,使其变为HSV。这将 return 一个 3D 矩阵,其色调、饱和度和值作为 3D 矩阵中的 2D 切片,很像 RGB 图像,其中每个切片代表红色、绿色和蓝色通道。让我们看看将图像转换为 HSV 后每个组件的样子:

im = imread('https://www.cdc.gov/dpdx/images/malaria/ovale/Po_gametocyte_thickB.jpg');
hsv = rgb2hsv(im2double(im));
figure;
for idx = 1 : 3
    subplot(1,3,idx);
    imshow(hsv(:,:,idx));
end

第一行代码从URL中读入一张图片。我将使用 Hoki 向您推荐的那个,因为它是处理起来最简单的一个。为了自我包容,这是原始图像的样子:

完成此操作后,我们将图像转换为 HSV 颜色 space。重要的是将图像转换为 double 精度并将每个分量标准化为 [0,1],这由 im2double 执行。接下来,我们生成一个新图形,并将每个组件放置在三列的一行中。第一列代表色调,下一列代表饱和度,最后一列代表值。这是我们看到的数字:

对于第一个图,看起来主色是紫色,无论是浅色还是深色,所以色调在这里对我们没有帮助。如果您查看 HSV 色轮:


(来源:hobbitsandhobos.com

标准化轮子,使其落在 [0,1] 之间,而不是 0 到 360 度之间。由于颜色 space 的性质,色调实际上表示为度数,但 MATLAB 将其标准化为 [0,1]。您可以看到紫色落在 [0.6,0.8] 的色调内,这对应于我向您展示的第一个显示图像色调的图形。如果您检查图像周围的像素,它们会在此范围内波动。因此,色调在这里对我们帮助不大。

肯定会帮助我们的是饱和度和价值成分。如果你看一下,深紫色像素的饱和度比背景的其余部分高,这是有道理的,因为深紫色比背景的其余部分具有更纯净的紫色版本。对于数值,可以看到深紫色的亮度比背景暗。

我们可以利用这两个点来分割出图像中的紫色。最简单的做法是设置饱和度和值平面的阈值,以便保留某个范围内的任何值,而丢弃超出范围的值。因此,您可以这样做:

sThresh = hsv(:,:,2) > 0.6 & hsv(:,:,2) < 0.9;
vThresh = hsv(:,:,3) > 0.4 & hsv(:,:,3) < 0.65;

我使用 impixelinfo 并将鼠标悬停在饱和度和值分量上以检查深紫色区域的值。看起来那些深紫色的像素的饱和度值介于 0.6 和 0.9 之间,而值分量的值介于 0.4 和 0.65 之间。上面的代码将创建两个二进制掩码,其中 true 表示像素满足我们的标准,而 false 表示不满足。因为我想将两者结合在一起并且不遗余力,所以让我们对掩码进行逻辑或操作以获得最终结果:

figure;
result = sThresh | vThresh;
imshow(result);

我们也会展示结果。这就是我们得到的:

如您所见,这做得很好,但是我们在最终结果中不希望有红色箭头的残余。为了做一些清理,我们可以使用形态学——特别是一个小 window 的开放过滤器,这样我们就不会影响我们想要的像素。我们可以使用 imopen to perform our opening operation for us. A morphological opening removes isolated pixels that appear around your image. You use what is called a structuring element 来查看图像的局部邻域。对于基础知识,任何与结构元素中包含的形状一样小的像素区域都将被删除。因为我们想保留其他对象的形状,我们可以尝试使用 5 x 5 磁盘结构元素来清理这些像素:

figure;
se = strel('disk', 2, 0);
final = imopen(result, se);
imshow(final);

这是我们得到的:

不错!我们需要修补一些漏洞,所以让我们用 imfill:

来填补这些漏洞
figure;
final_noholes = imfill(final, 'holes');
imshow(final_noholes);

这是我们得到的:

好的!所以我们有我们的面具。我们需要做的最后一件事是呈现图像,这样您就可以只显示原始图像中的深紫色,而不会显示其他颜色。这可以通过 bsxfun:

轻松实现
figure;
out = bsxfun(@times, im, uint8(final_noholes));
imshow(out);

以上操作采用您的蒙版,并将图像中的每个像素乘以该蒙版。我想指出的一件小事是,我们在上一步中找到的掩码需要转换为 uint8,因为 bsxfun 要求乘法(或您执行的任何操作)需要是同一类型。我们以 3D 形式复制此蒙版,以便您屏蔽掉不需要的 RGB 像素,只保留您要查找的像素。

这就是我们最终得到的:

如您所见,它并不完美,但足以让您入门。这些阈值很重要,但通过一些非常简单的阈值处理,我提取了大部分紫色像素。


为了方便您,这里是我上面写的代码,可以很容易地复制并粘贴到 MATLAB 中,供您使用 运行:

clear all; close all; clc;
im = imread('https://www.cdc.gov/dpdx/images/malaria/ovale/Po_gametocyte_thickB.jpg');
hsv = rgb2hsv(im2double(im));
figure;
for idx = 1 : 3
    subplot(1,3,idx);
    imshow(hsv(:,:,idx));
end

sThresh = hsv(:,:,2) > 0.6 & hsv(:,:,2) < 0.9;
vThresh = hsv(:,:,3) > 0.4 & hsv(:,:,3) < 0.65;

figure;
result = sThresh | vThresh;
imshow(result);

figure;
se = strel('disk', 2, 0);
final = imopen(result, se);
imshow(final);

figure;
final_noholes = imfill(final, 'holes');
imshow(final_noholes);

figure;
out = bsxfun(@times, im, uint8(final_noholes));
imshow(out);

祝你好运!

试试这个:

function main
    clc,clear

    A = imread('https://www.cdc.gov/dpdx/images/malaria/ovale/Po_gametocyte_thickB.jpg');
    subplot(1,2,1)
    imshow(A)

    RGB = [230 210 200];      % color you want
    e = 40;                   % color shift

    B = pix_in(A,RGB,e);
    B = B + 255.*uint8(~B);   % choosing white background
    subplot(1,2,2)
    imshow(B)
end

function B = pix_in(A,RGB,e)
    % select specific pixels in image
    % A - color image (3D matrix uint8)
    % RGB - [R G B] - color to select
    % e - color shift/deviation

    A = double(A);              % for same class operations (RGB - double)
    [m, n, ~] = size(A);
    RGB = reshape(RGB,1,1,3);
    RGB = repmat(RGB,m,n,1);    % creating 3D matrix
    b = abs(A-RGB) < e;         % logical 3D
    b = sum(b,3) == 3;          % if [R,G,B] of a pixel in range
    B = A.*repmat(b,1,1,3);     % selecting pixels those in range
    B = uint8(B);
end