使用 GoCV 进行黄色小圆圈检测

Yellow Small Circle Detection Using GoCV

我正在尝试检测带有各种颜色复选标记的圆圈。我要检测的是带有白色复选标记的黄色,以及将来带有 x 标记的红色圆圈。

到目前为止,我一直在尝试以下这些代码。这个使用霍夫圆法。

package main

import (
    "fmt"
    "image"
    "image/color"
    "os"

    "gocv.io/x/gocv"
)

func DetectCircles() {
    if len(os.Args) < 2 {
        fmt.Println("How to run:\n\tfind-circles [imgfile]")
        return
    }

    filename := os.Args[1]

    grey_window := gocv.NewWindow("grey window")
    grey_window.MoveWindow(600, 0)
    window := gocv.NewWindow("detected circles")
    defer grey_window.Close()
    defer window.Close()

    original_img := gocv.IMRead(filename, gocv.IMReadColor)
    defer original_img.Close()

    img := gocv.NewMat()
    defer img.Close()

    gocv.CvtColor(original_img, &img, gocv.ColorBGRToGray)

    gocv.MedianBlur(img, &img, 5)

    circles := gocv.NewMat()
    defer circles.Close()

    gocv.HoughCirclesWithParams(
        img,
        &circles,
        gocv.HoughGradient,
        1, // dp
        // float64(img.Rows()/8), // minDist
        26,
        200, // param1
        48,  // param2
        0,   // minRadius
        0,   // maxRadius
    )

    green := color.RGBA{0, 255, 0, 0}
    red := color.RGBA{255, 0, 0, 0}

    for i := 0; i < circles.Cols(); i++ {
        v := circles.GetVecfAt(0, i)
        // if circles are found
        if len(v) > 2 {
            x := int(v[0])
            y := int(v[1])
            r := int(v[2])

            gocv.Circle(&original_img, image.Pt(x, y), r, green, 2)
            gocv.Circle(&original_img, image.Pt(x, y), 2, red, 3)
        }
    }

    for {
        window.IMShow(original_img)

        if window.WaitKey(10) >= 0 {
            break
        }
    }
}

经过一些调整,我设法检测到一些像这样的更大的圆圈。

但是当我尝试使用更小的圆圈时仍然没有成功。

这些是我写的用来隔离颜色的代码。我所做的是在特定的 HSV 范围内添加一些颜色遮罩。

package main

import (
    "fmt"
    "image"
    "image/color"
    "os"

    "gocv.io/x/gocv"
)

func DetectCircles2() {
    if len(os.Args) < 2 {
        fmt.Println("How to run:\n\tgo run . [imgfile]")
        return
    }

    filename := os.Args[1]

    window := gocv.NewWindow("detected colors")
    window2 := gocv.NewWindow("end result")
    window3 := gocv.NewWindow("lower bound")
    window4 := gocv.NewWindow("upper bound")
    window2.MoveWindow(600, 0)
    window3.MoveWindow(0, 600)
    window4.MoveWindow(600, 600)
    defer window.Close()
    defer window2.Close()
    defer window3.Close()
    defer window4.Close()

    img := gocv.IMRead(filename, gocv.IMReadColor)
    defer img.Close()

    original_image := img.Clone()
    defer original_image.Close()

    gocv.MedianBlur(img, &img, 3)

    hsv_img := gocv.NewMat()
    defer hsv_img.Close()

    // yellow := gocv.NewScalar(0, 255, 255, 0)
    // yellow_mat := gocv.NewMatFromScalar(yellow, gocv.MatTypeCV8UC3)
    // gocv.CvtColor(yellow_mat, &yellow_mat, gocv.ColorBGRToHSV)
    // hsv := gocv.Split(yellow_mat)
    // fmt.Printf("H: %d S: %d V: %d\n", hsv[0].GetUCharAt(0, 0), hsv[1].GetUCharAt(0, 0), hsv[2].GetUCharAt(0, 0))

    gocv.CvtColor(img, &hsv_img, gocv.ColorBGRToHSV)
    img_rows, img_cols := hsv_img.Rows(), hsv_img.Cols()

    // lb1 := gocv.NewMatWithSizeFromScalar(gocv.NewScalar(0.0, 208.0, 94.0, 0.0), img_rows, img_cols, gocv.MatTypeCV8UC3)
    // ub1 := gocv.NewMatWithSizeFromScalar(gocv.NewScalar(179.0, 255.0, 255.0, 0.0), img_rows, img_cols, gocv.MatTypeCV8UC3)
    lb1 := gocv.NewMatWithSizeFromScalar(gocv.NewScalar(20.0, 50.0, 50.0, 0.0), img_rows, img_cols, gocv.MatTypeCV8UC3)
    ub1 := gocv.NewMatWithSizeFromScalar(gocv.NewScalar(40.0, 255.0, 255.0, 0.0), img_rows, img_cols, gocv.MatTypeCV8UC3)

    lb2 := gocv.NewMatWithSizeFromScalar(gocv.NewScalar(155.0, 100.0, 100.0, 0.0), img_rows, img_cols, gocv.MatTypeCV8UC3)
    ub2 := gocv.NewMatWithSizeFromScalar(gocv.NewScalar(180.0, 255.0, 255.0, 0.0), img_rows, img_cols, gocv.MatTypeCV8UC3)

    lower_bound := gocv.NewMat()
    upper_bound := gocv.NewMat()
    color_isolated_img := gocv.NewMat()
    circles := gocv.NewMat()
    defer lower_bound.Close()
    defer upper_bound.Close()
    defer color_isolated_img.Close()
    defer circles.Close()

    gocv.InRange(hsv_img, lb1, ub1, &lower_bound)
    gocv.InRange(hsv_img, lb2, ub2, &upper_bound)

    gocv.AddWeighted(lower_bound, 1.0, upper_bound, 1.0, 0.0, &color_isolated_img)
    gocv.GaussianBlur(color_isolated_img, &color_isolated_img, image.Pt(9, 9), 2, 2, gocv.BorderDefault)

    gocv.HoughCirclesWithParams(
        color_isolated_img,
        &circles,
        gocv.HoughGradient,
        1,
        float64(color_isolated_img.Rows()/8),
        100,
        20,
        0,
        0,
    )

    green := color.RGBA{0, 255, 0, 0}

    for i := 0; i < circles.Cols(); i++ {
        v := circles.GetVecfAt(0, i)
        fmt.Println(v)
        if len(v) > 2 {
            x := int(v[0])
            y := int(v[1])
            r := int(v[2])

            gocv.Circle(&original_image, image.Pt(x, y), r, green, 2)
        }
    }

    for {
        // window.IMShow(color_isolated_img)
        window2.IMShow(original_image)
        window3.IMShow(lower_bound)
        window4.IMShow(upper_bound)

        if window.WaitKey(10) >= 0 {
            break
        }
    }
}

这是结果。上面的代码只能检测到一个红色圆圈(应该是两个)和一个黄色圆圈。

我一直在尝试转换用 python 编写的轮廓检测只是为了迷惑 gocv API。我正在标记 gocv 和 opencv,希望这两个社区能帮助我正确检测彩色小圆圈。任何建议将被认真考虑。非常感谢。

所以我所做的是安装另一个由 vcaesar 称为 gcv 的库。有一个方法叫做FindAllImg,我只需要提供两张图片,一张是源图,在我的例子中是截图,另一张是需要在截图中搜索的模板图片。