【实战】opencv 文字区域的提取
时间:2018-11-08 06:05:06 +0800 CST 浏览:4860

preprocess(图片预处理),findTextRegion(查找和筛选文字区域)

golang_S1-l6gVIX.jpg

代码

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++版



如果这篇文章对你有所帮助,可以通过下边的“打赏”功能进行小额的打赏。

本网站部分内容来源于互联网,如有侵犯版权请来信告知,我们将立即处理。


来说两句吧