需求:扫描的文本图像由于人为因素,使用不能实现文本居中(内用区域靠边),影像图像美观;
解决思路:识别出本文区域,重新绘制到原图中心即可。
实现方案如下:
实现文本图像版型居中分六步:
第一:CvInvoke.CvtColor图像灰度化;
第二:CvInvoke.Threshold图像二值化;
第三:CvInvoke.FindContours边缘检测;
第四:遍历检测结果,使用CvInvoke.BoundingRectangle获取所有矩形区域;
第五:遍历所有得到的矩形区域确定文字区域;
第六:根据文字区域计算位置,根据新位置重新绘制图像。
扫描二维码关注公众号,回复:
10321540 查看本文章
private void button6_Click(object sender, EventArgs e)
{
//Dim imgCanny As Image(Of Gray, Byte) = New Image(Of Gray, Byte)(img.Width, img.Height, bkGrayWhite)
Bitmap graybtm;
Bitmap bitmap =new Bitmap(pictureBox2.Image);
List<Rectangle> rects;
Rectangle rect;
Point a = new Point(0, 0);
Point b = new Point(0, 0);
imageBox1.Image = FindBundingBox(bitmap, out graybtm, out rects);
//Image<Bgr, Byte> imageResult = pictureBox2.Image.CopyBlank();
Image<Bgr, byte> imageResult = new Image<Bgr, byte>(graybtm);
int i = 0;
foreach (Rectangle triangle in rects)
{
if (i == 0)
{
a.X = triangle.X;
a.Y = triangle.Y;
}
i++;
a.X = Math.Min(a.X, triangle.X);
a.Y = Math.Min(a.Y, triangle.Y);
b.X = Math.Max(b.X, triangle.X + triangle.Width);
b.Y = Math.Max(b.Y, triangle.Y + triangle.Height);
}
rect = new Rectangle(a.X,a.Y, b.X-a.X,b.Y-a.Y);
Pen mypen = new Pen(Color.Black, 1);//设置画笔的颜色及宽度
//imageResult.Draw(rect, new Bgr(Color.LightSteelBlue), 2);
Bitmap imageResult_s = new Bitmap(pictureBox2.Image);
Graphics g = Graphics.FromImage(imageResult_s);
g.Clear(Color.White);
g.DrawImage(pictureBox2.Image, new Rectangle(pictureBox2.Image.Width / 2 - rect.Width / 2, rect.Y, rect.Width, rect.Height), rect, GraphicsUnit.Pixel);
g.DrawRectangle(new Pen(Color.Red, 2), rect);
g.Dispose();
//ppp();
pictureBox2.Image = imageResult_s;
}
获取区域:
private Bitmap FindBundingBox(Bitmap bitmap, out Bitmap graybtm, out List<Rectangle> rects)
{
Image<Bgr, byte> img = new Image<Bgr, byte>(bitmap);
Image<Gray, byte> gray = new Image<Gray, byte>(img.Width, img.Height);
Image<Bgr, byte> resuImage = new Image<Bgr, byte>(img.Width, img.Height);
Image<Gray, byte> dnc = new Image<Gray, byte>(img.Width, img.Height);
CvInvoke.CvtColor(img, gray, ColorConversion.Bgra2Gray);//灰度化
//做一下膨胀,x与y方向都做,但系数不同
var kernal = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(4, 4), new Point(1, 1));
CvInvoke.Erode(gray, gray, kernal, new Point(0, 2), 1, BorderType.Default, new MCvScalar());
//CvInvoke.Canny(gray, gray, 100, 60);
CvInvoke.Threshold(gray, gray, 100, 255, ThresholdType.BinaryInv | ThresholdType.Otsu);//二值化
//检测连通域,每一个连通域以一系列的点表示,FindContours方法只能得到第一个域
graybtm = gray.ToBitmap();
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(gray, contours, dnc, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
var color = new MCvScalar(0, 0, 255);
Console.WriteLine(contours.Size);
rects = new List<Rectangle>();
//开始遍历
for (int i = 0; i < contours.Size; i++)
{
//得到这个连通区域的外接矩形
var rect = CvInvoke.BoundingRectangle(contours[i]);
//如果高度不足,或者长宽比太小,认为是无效数据,否则把矩形画到原图上
if (rect.Height > 2 && rect.Width > 2)
{
rects.Add(rect);
CvInvoke.DrawContours(resuImage, contours, i, color);
}
}
return img.ConcateVertical(resuImage).ToBitmap();
}
参考:http://www.cnblogs.com/daxiongblog/p/5776636.html