preprocess(图片预处理),findTextRegion(查找和筛选文字区域)
package main
import (
"fmt"
"image"
"image/color"
"os"
"gocv.io/x/gocv"
)
func main() {
if len(os.Args) < 2 {
fmt.Printf("How to run:\n\t%s [imageFile]\n", os.Args[0])
return
}
filename := os.Args[1]
img := gocv.IMRead(filename, gocv.IMReadColor)
gray := gocv.NewMat()
defer gray.Close()
// 1、转化成灰度图
gocv.CvtColor(img, &gray, gocv.ColorBGRToGray)
// 2、形态学变换的预处理,得到可以查找矩形的图片
dilation := preprocess(gray)
defer dilation.Close()
// 3、查找和筛选文字区域
rects := findTextRegion(dilation)
// 4、用绿线画出这些找到的轮廓
for _, rect := range rects {
tmpRects := make([][]image.Point, 0)
tmpRects = append(tmpRects, rect)
gocv.DrawContours(&img, tmpRects, 0, color.RGBA{0, 255, 0, 255}, 2)
}
// 5.显示带轮廓的图像
gocv.IMWrite("imgDrawRect.jpg", img)
// window := gocv.NewWindow("img")
// for {
// window.IMShow(img)
// if window.WaitKey(1) >= 0 {
// break
// }
// }
}
func preprocess(gray gocv.Mat) gocv.Mat {
// 1. Sobel算子,x方向求梯度
sobel := gocv.NewMat()
defer sobel.Close()
gocv.Sobel(gray, &sobel, int(gocv.MatTypeCV8U), 1, 0, 3, 1, 0, gocv.BorderDefault)
// 二值化
binary := gocv.NewMat()
defer binary.Close()
gocv.Threshold(sobel, &binary, 0, 255, gocv.ThresholdOtsu+gocv.ThresholdBinary)
// 3. 膨胀和腐蚀操作的核函数
// 可以调节
element1 := gocv.GetStructuringElement(gocv.MorphRect, image.Point{30, 9})
// 可以调节
element2 := gocv.GetStructuringElement(gocv.MorphRect, image.Point{24, 4})
// 4. 膨胀一次,让轮廓突出
dilation := gocv.NewMat()
defer dilation.Close()
gocv.Dilate(binary, &dilation, element2)
// 5. 腐蚀一次,去掉细节,如表格线等。注意这里去掉的是竖直的线
erosion := gocv.NewMat()
defer erosion.Close()
gocv.Erode(dilation, &erosion, element1)
// 6. 再次膨胀,让轮廓明显一些
dilation2 := gocv.NewMat()
// defer dilation2.Close()
gocv.Dilate(erosion, &dilation2, element2)
// 存储中间图片
gocv.IMWrite("binary.png", binary)
gocv.IMWrite("dilation.png", dilation)
gocv.IMWrite("erosion.png", erosion)
gocv.IMWrite("dilation2.png", dilation2)
return dilation2
}
func findTextRegion(img gocv.Mat) [][]image.Point {
// 1. 查找轮廓
rects := make([][]image.Point, 0)
contours := gocv.FindContours(img, gocv.RetrievalTree, gocv.ChainApproxSimple)
for _, cnt := range contours {
// 计算该轮廓的面积
area := gocv.ContourArea(cnt)
// 面积小的都筛选掉
// 可以调节 1000
if area < 700 {
continue
}
// 轮廓近似,作用很小
epsilon := 0.001 * gocv.ArcLength(cnt, true)
// approx := gocv.ApproxPolyDP(cnt, epsilon, true)
_ = gocv.ApproxPolyDP(cnt, epsilon, true)
// 找到最小矩形,该矩形可能有方向
rect := gocv.MinAreaRect(cnt)
// 计算高和宽
mWidth := float64(rect.BoundingRect.Max.X - rect.BoundingRect.Min.X)
mHeight := float64(rect.BoundingRect.Max.Y - rect.BoundingRect.Min.Y)
// 筛选那些太细的矩形,留下扁的
// 可以调节 mHeight > (mWidth * 1.2)
if mHeight > (mWidth * 0.9) {
continue
}
// 符合条件的rect添加到rects集合中
rects = append(rects, rect.Contour)
}
return rects
}
上面代码注释中有四处参数是可以自行调节的,数值调节直接影响定位区域好坏。大家可自行测试
我就不上配图了,因为效果都是相差不大的。
python版
c++版
如果这篇文章对你有所帮助,可以通过下边的“打赏”功能进行小额的打赏。
本网站部分内容来源于互联网,如有侵犯版权请来信告知,我们将立即处理。