gpt4 book ai didi

c# - Emgucv 自动裁剪检测到的形状

转载 作者:行者123 更新时间:2023-12-02 17:19:45 28 4
gpt4 key购买 nike

我有一个应用程序,它将用于从扫描的文档中裁剪空格,例如 this image .我想要做的是只提取卡片并删除所有白色/空白区域。我正在使用 Emgucv FindContours 来执行此操作,目前我能够在图像中找到卡片轮廓和扫描仪捕获的一些噪声,如下所示。
enter image description here
我的问题是如何裁剪找到的最大轮廓或如何通过删除其他轮廓和空白/空白来提取它?或者也许可以使用轮廓索引?
编辑:也许另一种可能的解决方案是是否可以将轮廓绘制到另一个图片框。
这是我正在使用的代码:

Image<Bgr, byte> imgInput;
Image<Bgr, byte> imgCrop;

private void abrirToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog dialog = new OpenFileDialog();

if (dialog.ShowDialog() ==DialogResult.OK)
{
imgInput = new Image<Bgr, byte>(dialog.FileName);
pictureBox1.Image = imgInput.Bitmap;

imgCrop = imgInput;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void shapeToolStripMenuItem_Click(object sender, EventArgs e)
{
if (imgCrop == null)
{
return;
}

try
{
var temp = imgCrop.SmoothGaussian(5).Convert<Gray, byte>().ThresholdBinaryInv(new Gray(230), new Gray(255));
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
Mat m = new Mat();

CvInvoke.FindContours(temp, contours, m, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);

for (int i = 0; i < contours.Size; i++)
{
double perimeter = CvInvoke.ArcLength(contours[i], true);
VectorOfPoint approx = new VectorOfPoint();
CvInvoke.ApproxPolyDP(contours[i], approx, 0.04 * perimeter, true);

CvInvoke.DrawContours(imgCrop, contours, i, new MCvScalar(0, 0, 255), 2);
pictureBox2.Image = imgCrop.Bitmap;
}

}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

最佳答案

我会在 C++ 中给你答案,但在 Emgu CV 中应该可以使用相同的操作.
我提出以下方法: 使用 分割(即分离)目标对象HSV 色彩空间。计算 二进制掩码 对于感兴趣的对象。获取 最大的 Blob 在二进制掩码中,这应该是卡片。计算 边界框 的卡片。 裁剪 输入图像中的卡片
好的,首先获取(或读取)输入图像。申请 median blur过滤器,它将有助于消除您在输入中看到的高频噪声(小灰色 Blob )。要调整的主要参数是sizekernel (或滤镜光圈)但要小心——高值会导致强烈的效果,并可能会破坏您的图像:

  //read input image:
std::string imageName = "C://opencvImages//yoshiButNotYoshi.png";
cv::Mat imageInput = cv::imread( imageName );

//apply a median blur filter, the size of the kernel is 5 x 5:
cv::Mat blurredImage;
cv::medianBlur ( imageInput, blurredImage, 5 );
这是模糊过滤器的结果(嵌入的图像已调整大小):

接下来,分割图像。利用背景是白色的事实,而其他一切(主要是感兴趣的对象)都有一些颜色信息。您可以使用 HSV色彩空间。首先,转换 BGR图像到 HSV :
  //BGR to HSV conversion:
cv::Mat hsvImg;
cv::cvtColor( blurredImage, hsvImg, CV_RGB2HSV );
HSV颜色空间对颜色信息的编码方式与典型的 BGR/RGB 不同。色彩空间。它相对于其他颜色模型的优势在很大程度上取决于应用程序,但总的来说,它在使用色调渐变时更加强大。我将尝试为感兴趣的对象获取基于 HSV 的二进制掩码。
在二进制掩码中,您对输入图像感兴趣的所有内容都在 white 中着色, black 中的所有其他内容(或相反亦然)。您可以使用 inRange 获取此掩码。功能。但是,您必须指定将在输出掩码中呈现为白色(或黑色)的颜色范围。对于您的图像,并使用 HSV 颜色模型,这些值是:
  cv::Scalar minColor( 0, 0, 100 ); //the lower range of colors
cv::Scalar maxColor( 0, 0, 255 ); //the upper range of colors
现在,获取二进制掩码:
  //prepare the binary mask:
cv::Mat binaryMask;
//create the binary mask using the specified range of color
cv::inRange( hsvImg, minColor, maxColor, binaryMask );
//invert the mask:
binaryMask = 255 - binaryMask;
你得到这个图像:

现在,您可以通过 morphological filtering 去除一些噪声(在模糊滤镜中幸存下来)。 .形态过滤器本质上是应用于二值(或灰色)图像的逻辑规则。它们在输入中采用像素的“邻域”并应用逻辑函数来获得输出。它们在清理二进制图像时非常方便。我将应用一系列逻辑过滤器来实现这一点。
我先 erode图像,然后 dilate它使用 3 iterations . structuring elementrectangle大小 3 x 3 :
  //apply some morphology the clean the binary mask a little bit:
cv::Mat SE = cv::getStructuringElement( cv::MORPH_RECT, cv::Size(3, 3) );
int morphIterations = 3;
cv::morphologyEx( binaryMask, binaryMask, cv::MORPH_ERODE, SE, cv::Point(-1,-1), morphIterations );
cv::morphologyEx( binaryMask, binaryMask, cv::MORPH_DILATE, SE, cv::Point(-1,-1), morphIterations );
你得到这个输出。看看嘈杂的 Blob 是如何消失的:

现在,很酷的部分来了。您可以遍历所有 contours在此图像中并获取 最大 他们所有人中。这是我经常执行的典型操作,因此,我编写了一个函数来执行此操作。它被称为 findBiggestBlob .稍后我将介绍该功能。查看找到并提取最大 blob 后得到的结果:
  //find the biggest blob in the binary image:
cv::Mat biggestBlob = findBiggestBlob( binaryMask );
你得到这个:

现在,您可以获得 bounding box使用 boundingRect 的最大 blob :
  //Get the bounding box of the biggest blob:
cv::Rect bBox = cv::boundingRect( biggestBlob );
让我们画 bounding box在输入图像上:
  cv::Mat imageClone = imageInput.clone();
cv::rectangle( imageClone, bBox, cv::Scalar(255,0,0), 2 );

最后,让我们从输入图像中裁剪出卡片:
  cv::Mat croppedImage = imageInput( bBox );
这是裁剪后的输出:

这是 findBiggestBlob 的代码功能。这个想法只是计算二进制输入中的所有轮廓,计算它们的面积并存储具有最大面积的轮廓:
//Function to get the largest blob in a binary image:
cv::Mat findBiggestBlob( cv::Mat &inputImage ){

cv::Mat biggestBlob = inputImage.clone();

int largest_area = 0;
int largest_contour_index = 0;

std::vector< std::vector<cv::Point> > contours; // Vector for storing contour
std::vector< cv::Vec4i > hierarchy;

// Find the contours in the image
cv::findContours( biggestBlob, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

for( int i = 0; i < (int)contours.size(); i++ ) {

//Find the area of the contour
double a = cv::contourArea( contours[i], false);
//Store the index of largest contour:
if( a > largest_area ){
largest_area = a;
largest_contour_index = i;
}

}

//Once you get the biggest blob, paint it black:
cv::Mat tempMat = biggestBlob.clone();
cv::drawContours( tempMat, contours, largest_contour_index, cv::Scalar(0),
CV_FILLED, 8, hierarchy );

//Erase the smaller blobs:
biggestBlob = biggestBlob - tempMat;
tempMat.release();
return biggestBlob;
}

关于c# - Emgucv 自动裁剪检测到的形状,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62866191/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com