我正在做一个使用图像处理处理脑损伤的项目。为了提高其准确性,我只需要从头骨中提取大脑物质。
使用 EmguCV 我能够识别内部和外部轮廓(蓝色和深蓝色)。有没有办法将这些识别的轮廓提取到另一幅图像中?
Image<Gray, byte> grayImage = new Image<Gray, byte>(bitmap);
Image<Bgr, byte> color = new Image<Bgr, byte>(bitmap);
grayImage = grayImage.ThresholdBinary(new Gray(220), new Gray(255));
using (MemStorage storage = new MemStorage())
{
for (Contour<Point> contours = grayImage.FindContours(
Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE, storage); contours != null; contours = contours.HNext)
{
Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.015, storage);
if (currentContour.BoundingRectangle.Width > 20)
{
CvInvoke.cvDrawContours(color, contours, new MCvScalar(100), new MCvScalar(255), -1, 2, Emgu.CV.CvEnum.LINE_TYPE.EIGHT_CONNECTED, new Point(0, 0));
}
}
}
EmguCV 2.2.2
预期输出:
实现这一目标的一个好方法是使用掩码,如这个 C++ 示例中所示。我以这张图片为例:
它是根据 CC-NC-SA 许可证获得许可的,请参阅源网站。 首先使用
CvInvoke.FindContours
提取头骨的内部轮廓:
然后根据内部轮廓使用
CvInvoke.FillPoly
创建蒙版:
最后你可以将原始图像复制到蒙版图像中,你将只得到头骨的内部。
完整代码可在此处获取。请注意,我使用 EmguCV 4.8.1,因此需要进行一些更改。
using System.Drawing;
using System.IO;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;
namespace emgutest
{
class Program
{
private static string testFile = "test.jpg";
static void Main(string[] args)
{
Bitmap testImage;
using (var stream = new FileStream(testFile, FileMode.Open))
{
testImage = (Bitmap)Image.FromStream(stream);
}
var color = testImage.ToImage<Bgr, byte>();
var grayImage = color.Convert<Gray, byte>();
grayImage = grayImage.ThresholdBinary(new Gray(220), new Gray(255));
// Extract contour
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
Mat hierarchy = new Mat();
CvInvoke.FindContours(grayImage, contours, hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxSimple);
// Draw contour on original image
var color_contour = color.Copy();
CvInvoke.DrawContours(color_contour, contours, 1, new MCvScalar(255, 0, 0), 2); // Inner contour (-1 for all, 0 for outer)
color_contour.Save("output_contour.jpg");
// Create mask
Mat output_image = color.Mat;
VectorOfVectorOfPoint inner_contours = new VectorOfVectorOfPoint(contours[1]); // Select inner contour only
Mat blackedOut = new Mat(color.Size, DepthType.Cv8U, 3);
blackedOut.SetTo(new MCvScalar(0, 0, 0)); // Full black image
Mat mask = new Mat(grayImage.Size, DepthType.Cv8U, 1);
CvInvoke.FillPoly(mask, inner_contours, new MCvScalar(255), LineType.AntiAlias);
CvInvoke.DrawContours(mask, contours, -1, new MCvScalar(0), 2, LineType.Filled);
// Copy image to mask
output_image.CopyTo(blackedOut, mask);
blackedOut.Save("output.jpg");
}
}
}