如何以编程方式实时执行图像分割
How to programatically perform image segmentation in real-time
我目前正在尝试分割血管的超声图像(视频帧),例如正下方的图像。
在饱和通道上使用一个简单的二元滤波器(下面的代码),我得到了一个不令人满意的结果,如下面的第三张图。当然,我尝试用 OpenCV Imgproc.dilate()
将过滤区域扩大几个像素,但这样做的问题是它增加了过滤区域与相邻黑色区域连接的机会很多,这会导致不可接受的精度损失在随后的计算中。
如果在这种分割方面有经验的人能给我指出一个很好的技术来实现接近下面第二张图像的实时效果(30 frames/sec),那就是真不错!
如何分割这个基本图像:
所以看起来更像这个手绘分割:
虽然饱和通道上的简单二元滤波器不是那么好:
我的饱和度过滤函数(java):
public static Mat threshold_onsat (Mat frame, Mat hsv_frame, int saturation){
double sat = (double) saturation;
List<Mat> lhsv = new ArrayList<Mat>(3);
Mat masked = new Mat();
Core.split(hsv_frame, lhsv);
Mat sat_mask = lhsv.get(1);
Imgproc.threshold(sat_mask, sat_mask, sat, 255D, Imgproc.THRESH_BINARY_INV);
frame.copyTo(masked, sat_mask);
return masked;
}
我想您可能想要了解一种称为活动形状的更复杂的方法。虽然我不是医学图像处理方面的专家,但我知道我的一个朋友已经成功地使用这种方法来分割腹部动脉瘤的内外表面(哎哟),这似乎与您的应用程序松散相关。您可以找到有关主题 in this paper.
的更多信息
我认为您可以坚持使用当前的饱和度过滤器,因为它可以识别您所在的区域。但是然后使用形态学操作对其进行扩充。我会先腐蚀再膨胀。 (不仅仅是您尝试时自行扩张)。腐蚀步骤消除了噪声,然后膨胀使掩码变大。我实际上连续做了两次扩张,以创建一个更好看的面具。
我在 matlab 中做了一个快速测试作为概念验证。我只使用 matlab 是因为它的测试速度非常快(~5 分钟),但我知道 openCV 具有非常相似的功能(dilation/erosion 元素、imerode、imdilate)。阅读代码注释,有一些关于该过程的好信息。代码本身并不重要,仅供参考。更重要的部分是了解它的作用。我试图将我的 "mask" 与您的面具相匹配,但我根本没有使用您的轮廓区域。
segmented_im = rgb2gray(imread('binary_saturation_image.png'));
segmented_im = segmented_im(3:end,:);
orig_im = rgb2gray(imread('base_image.png'));
%i recreated your mask here, it looked like your mask had 0 values so thats
%what i used. it's 1 in region of interest and 0 elsewhere, this is
%important to take note of
mask = (segmented_im==0);
%creates a structuing element for our morphological operators, Another way
%to thing of this is like a nearest neighbor operation. This structuring
%element defines what your neighbors are, we are using a disk with radius 7
% in openCV this is your erosion/dilation element, the closest would be MORPH_ELLIPSE
%but using different elements and sizes may you get a better shape
%also using different shapes for the erosion vs dilation may help you
%further shape your mask
se = strel('disk',7,0);
%now we erode the image (this expands the 0 regions) we do this to remove
%noise, those small little dots around the mask
mask_erode = imerode(mask,se);
%now we dilate the image (expands the 1 regions) this will give us a more
%rounded mask
mask_dilate1 = imdilate(mask_erode,se);
%we do it one more time to round out the shape more
mask_dilate2 = imdilate(mask_dilate1,se);
%now we invert the mask (so the areas of interest are 0, and 1 elsewhere)
invert_mask = uint8(~mask_dilate2);
%we multiply the original image by our mask (so the area of interest has
%zero values)
newly_segmented = orig_im .* invert_mask;
figure()
subplot(2,3,1);imshow(orig_im);title('base image');
subplot(2,3,2);imshow(mask);title('mask');
subplot(2,3,3);imshow(mask_erode);title('mask erode image');
subplot(2,3,4);imshow(mask_dilate1);title('mask dilate1 image');
subplot(2,3,5);imshow(mask_dilate2);title('mask dilate2 image');
subplot(2,3,6);imshow(newly_segmented);title('newly segmented image');
既然有人把这个问题加入了他的收藏夹,我会post我最好的引导:
这种问题的最佳解决方案似乎确实是主动轮廓分割,为此我从理工学院的生物医学成像组找到了this Esnake implementation洛桑。它是一个ImageJ插件,但我希望能够将它实现到我自己的应用程序中。
我目前正在尝试分割血管的超声图像(视频帧),例如正下方的图像。
在饱和通道上使用一个简单的二元滤波器(下面的代码),我得到了一个不令人满意的结果,如下面的第三张图。当然,我尝试用 OpenCV Imgproc.dilate()
将过滤区域扩大几个像素,但这样做的问题是它增加了过滤区域与相邻黑色区域连接的机会很多,这会导致不可接受的精度损失在随后的计算中。
如果在这种分割方面有经验的人能给我指出一个很好的技术来实现接近下面第二张图像的实时效果(30 frames/sec),那就是真不错!
如何分割这个基本图像:
所以看起来更像这个手绘分割:
虽然饱和通道上的简单二元滤波器不是那么好:
我的饱和度过滤函数(java):
public static Mat threshold_onsat (Mat frame, Mat hsv_frame, int saturation){
double sat = (double) saturation;
List<Mat> lhsv = new ArrayList<Mat>(3);
Mat masked = new Mat();
Core.split(hsv_frame, lhsv);
Mat sat_mask = lhsv.get(1);
Imgproc.threshold(sat_mask, sat_mask, sat, 255D, Imgproc.THRESH_BINARY_INV);
frame.copyTo(masked, sat_mask);
return masked;
}
我想您可能想要了解一种称为活动形状的更复杂的方法。虽然我不是医学图像处理方面的专家,但我知道我的一个朋友已经成功地使用这种方法来分割腹部动脉瘤的内外表面(哎哟),这似乎与您的应用程序松散相关。您可以找到有关主题 in this paper.
的更多信息我认为您可以坚持使用当前的饱和度过滤器,因为它可以识别您所在的区域。但是然后使用形态学操作对其进行扩充。我会先腐蚀再膨胀。 (不仅仅是您尝试时自行扩张)。腐蚀步骤消除了噪声,然后膨胀使掩码变大。我实际上连续做了两次扩张,以创建一个更好看的面具。
我在 matlab 中做了一个快速测试作为概念验证。我只使用 matlab 是因为它的测试速度非常快(~5 分钟),但我知道 openCV 具有非常相似的功能(dilation/erosion 元素、imerode、imdilate)。阅读代码注释,有一些关于该过程的好信息。代码本身并不重要,仅供参考。更重要的部分是了解它的作用。我试图将我的 "mask" 与您的面具相匹配,但我根本没有使用您的轮廓区域。
segmented_im = rgb2gray(imread('binary_saturation_image.png'));
segmented_im = segmented_im(3:end,:);
orig_im = rgb2gray(imread('base_image.png'));
%i recreated your mask here, it looked like your mask had 0 values so thats
%what i used. it's 1 in region of interest and 0 elsewhere, this is
%important to take note of
mask = (segmented_im==0);
%creates a structuing element for our morphological operators, Another way
%to thing of this is like a nearest neighbor operation. This structuring
%element defines what your neighbors are, we are using a disk with radius 7
% in openCV this is your erosion/dilation element, the closest would be MORPH_ELLIPSE
%but using different elements and sizes may you get a better shape
%also using different shapes for the erosion vs dilation may help you
%further shape your mask
se = strel('disk',7,0);
%now we erode the image (this expands the 0 regions) we do this to remove
%noise, those small little dots around the mask
mask_erode = imerode(mask,se);
%now we dilate the image (expands the 1 regions) this will give us a more
%rounded mask
mask_dilate1 = imdilate(mask_erode,se);
%we do it one more time to round out the shape more
mask_dilate2 = imdilate(mask_dilate1,se);
%now we invert the mask (so the areas of interest are 0, and 1 elsewhere)
invert_mask = uint8(~mask_dilate2);
%we multiply the original image by our mask (so the area of interest has
%zero values)
newly_segmented = orig_im .* invert_mask;
figure()
subplot(2,3,1);imshow(orig_im);title('base image');
subplot(2,3,2);imshow(mask);title('mask');
subplot(2,3,3);imshow(mask_erode);title('mask erode image');
subplot(2,3,4);imshow(mask_dilate1);title('mask dilate1 image');
subplot(2,3,5);imshow(mask_dilate2);title('mask dilate2 image');
subplot(2,3,6);imshow(newly_segmented);title('newly segmented image');
既然有人把这个问题加入了他的收藏夹,我会post我最好的引导:
这种问题的最佳解决方案似乎确实是主动轮廓分割,为此我从理工学院的生物医学成像组找到了this Esnake implementation洛桑。它是一个ImageJ插件,但我希望能够将它实现到我自己的应用程序中。