首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >gocv:如何使用opencv从蓝色背景中删除图像

gocv:如何使用opencv从蓝色背景中删除图像
EN

Stack Overflow用户
提问于 2018-03-12 17:46:47
回答 3查看 4.5K关注 0票数 3

我开始和gocv一起玩。我试图找出一件简单的事情:如何从有一定颜色背景的图像中剔除一个物体。在这种情况下,物体是比萨饼,背景颜色是蓝色。

我使用InRange函数(inRange in OpenCV)定义蓝色的上、下阈值以创建掩码,然后使用CopyToWithMask函数(OpenCV中的copyTo)将掩码应用到原始图像上。我希望结果是蓝色背景与比萨饼削减出来。

代码非常简单:

代码语言:javascript
复制
package main

import (
    "fmt"
    "os"

    "gocv.io/x/gocv"
)

func main() {
    imgPath := "pizza.png"
    // read in an image from filesystem
    img := gocv.IMRead(imgPath, gocv.IMReadColor)
    if img.Empty() {
        fmt.Printf("Could not read image %s\n", imgPath)
        os.Exit(1)
    }
    // Create a copy of an image
    hsvImg := img.Clone()

    // Convert BGR to HSV image
    gocv.CvtColor(img, hsvImg, gocv.ColorBGRToHSV)
    lowerBound := gocv.NewMatFromScalar(gocv.NewScalar(110.0, 100.0, 100.0, 0.0), gocv.MatTypeCV8U)
    upperBound := gocv.NewMatFromScalar(gocv.NewScalar(130.0, 255.0, 255.0, 0.0), gocv.MatTypeCV8U)

    // Blue mask
    mask := gocv.NewMat()
    gocv.InRange(hsvImg, lowerBound, upperBound, mask)

    // maskedImg: output array that has the same size and type as the input arrays.
    maskedImg := gocv.NewMatWithSize(hsvImg.Rows(), hsvImg.Cols(), gocv.MatTypeCV8U)
    hsvImg.CopyToWithMask(maskedImg, mask)

    // save the masked image
    newImg := gocv.NewMat()
    // Convert back to BGR before saving
    gocv.CvtColor(maskedImg, newImg, gocv.ColorHSVToBGR)
    gocv.IMWrite("no_pizza.jpeg", newImg)
}

然而,所得到的图像基本上是完全黑色的,除了一点披萨边缘的暗示:

至于选择的蓝色上下限,我遵循了官方文档中提到的指南。

代码语言:javascript
复制
blue = np.uint8([[[255, 0, 0]]])
hsv_blue = cv2.cvtColor(blue, cv2.COLOR_BGR2HSV)
print(hsv_blue)

[[[120 255 255]]]

现在取H-10,100,100和H+10,255,255分别作为下界和上界。

我肯定我错过了一些基本的东西,但不知道它是什么。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-04-17 21:27:15

所以我花了相当长的时间来找出我错过了什么,最后找到了我的问题的答案,以防有人感兴趣。我现在更清楚为什么这个问题没有得到回答,因为由于gocv API的存在,它的解决方案是相当疯狂的。

下面是我必须编写的代码,以获得我想要的结果:

代码语言:javascript
复制
package main

import (
    "fmt"
    "os"
    "path/filepath"

    "gocv.io/x/gocv"
)

func main() {
    // read image
    pizzaPath := filepath.Join("pizza.png")
    pizza := gocv.IMRead(pizzaPath, gocv.IMReadColor)
    if pizza.Empty() {
        fmt.Printf("Failed to read image: %s\n", pizzaPath)
        os.Exit(1)
    }
    // Convert BGR to HSV image (dont modify the original)
    hsvPizza := gocv.NewMat()
    gocv.CvtColor(pizza, &hsvPizza, gocv.ColorBGRToHSV)
    pizzaChannels, pizzaRows, pizzaCols := hsvPizza.Channels(), hsvPizza.Rows(), hsvPizza.Cols()
    // define HSV color upper and lower bound ranges
    lower := gocv.NewMatFromScalar(gocv.NewScalar(110.0, 50.0, 50.0, 0.0), gocv.MatTypeCV8UC3)
    upper := gocv.NewMatFromScalar(gocv.NewScalar(130.0, 255.0, 255.0, 0.0), gocv.MatTypeCV8UC3)
    // split HSV lower bounds into H, S, V channels
    lowerChans := gocv.Split(lower)
    lowerMask := gocv.NewMatWithSize(pizzaRows, pizzaCols, gocv.MatTypeCV8UC3)
    lowerMaskChans := gocv.Split(lowerMask)
    // split HSV lower bounds into H, S, V channels
    upperChans := gocv.Split(upper)
    upperMask := gocv.NewMatWithSize(pizzaRows, pizzaCols, gocv.MatTypeCV8UC3)
    upperMaskChans := gocv.Split(upperMask)
    // copy HSV values to upper and lower masks
    for c := 0; c < pizzaChannels; c++ {
        for i := 0; i < pizzaRows; i++ {
            for j := 0; j < pizzaCols; j++ {
                lowerMaskChans[c].SetUCharAt(i, j, lowerChans[c].GetUCharAt(0, 0))
                upperMaskChans[c].SetUCharAt(i, j, upperChans[c].GetUCharAt(0, 0))
            }
        }
    }
    gocv.Merge(lowerMaskChans, &lowerMask)
    gocv.Merge(upperMaskChans, &upperMask)
    // global mask
    mask := gocv.NewMat()
    gocv.InRange(hsvPizza, lowerMask, upperMask, &mask)
    // cut out pizza mask
    pizzaMask := gocv.NewMat()
    gocv.Merge([]gocv.Mat{mask, mask, mask}, &pizzaMask)
    // cut out the pizza and convert back to BGR
    gocv.BitwiseAnd(hsvPizza, pizzaMask, &hsvPizza)
    gocv.CvtColor(hsvPizza, &hsvPizza, gocv.ColorHSVToBGR)
    // write image to filesystem
    outPizza := "no_pizza.jpeg"
    if ok := gocv.IMWrite(outPizza, hsvPizza); !ok {
        fmt.Printf("Failed to write image: %s\n", outPizza)
        os.Exit(1)
    }
    // write pizza mask to filesystem
    outPizzaMask := "no_pizza_mask.jpeg"
    if ok := gocv.IMWrite(outPizzaMask, mask); !ok {
        fmt.Printf("Failed to write image: %s\n", outPizza)
        os.Exit(1)
    }
}

这段代码产生了我想要的结果:

我还将添加另一张图片,显示im

现在,让我们开始编码。gocv API函数InRange()不接受像OpenCV 有吗?那样的Scalar,所以您必须执行所有疯狂的图像通道分割和合并舞蹈,因为您需要将Mat作为下界和上限传递给InRange();这些Mat掩码必须有确切的通道数作为运行InRange()的图像。

这就引出了另一个重要的问题:在为这个任务分配Scalars时,我最初使用的是gocv.MatTypeCV8U类型,它表示单个通道的颜色--对于有三个通道的HSV图像来说还不够--这是通过使用gocv.MatTypeCV8UC3类型固定的。

如果我可以在gocv.Scalar中输入gocv.InRange(),那么许多锅炉板代码就会消失;所有用于拆分和重新组装创建下界和上界通道所需的通道的不必要的gocv.NewMat()分配也会消失。

票数 5
EN

Stack Overflow用户

发布于 2018-03-13 03:20:13

具有给定范围的inRange非常适合我。我不熟悉Go,但下面是我的python代码:

代码语言:javascript
复制
import numpy as py
import cv2

img = cv2.imread("pizza.png")

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (110, 100, 100), (130, 255, 255))
inv_mask = cv2.bitwise_not(mask)

pizza = cv2.bitwise_and(img, img, mask=inv_mask)

cv2.imshow("img", img)
cv2.imshow("mask", mask)
cv2.imshow("pizza", pizza)
cv2.imshow("inv mask", inv_mask)
cv2.waitKey()

这里有几个注释:

  • inRange返回蓝色背景,因此我们需要将其反转以显示对象的掩码(如果您需要该对象)。
  • 您不需要在hsvImg上应用掩码并转换为BGR,您可以直接在原始图像(已经是BGR )上应用掩码。
  • Python没有CopyToWithMask,所以我使用等效的bitwise_and。您可以在Go中检查此函数,但我怀疑不会有任何不同。
票数 3
EN

Stack Overflow用户

发布于 2018-03-13 01:16:11

这是我用Python做的,因为我不知道去.

让我先解释一下。

(1)图像已转为灰度图像。

(2)应用Canny边缘

(3 - 4)创建了内核,并使用它进行扩展和关闭操作。

(5)找到轮廓

(6)制作和应用掩码

(7)种植和拯救了该地区

以下是代码:

代码语言:javascript
复制
import cv2
import numpy as np

image = cv2.imread("image.png")
copy = image.copy()

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow('Gray', gray)
cv2.waitKey(0)

edged = cv2.Canny(gray, 10, 250)
cv2.imshow('Edged', edged)
cv2.waitKey(0)

kernel = np.ones((5, 5), np.uint8)

dilation = cv2.dilate(edged, kernel, iterations=1)
cv2.imshow('Dilation', dilation)
cv2.waitKey(0)

closing = cv2.morphologyEx(dilation, cv2.MORPH_CLOSE, kernel)
cv2.imshow('Closing', closing)
cv2.waitKey(0)

# if using OpenCV 4, remove image variable from below
image, cnts, hiers = cv2.findContours(closing, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cont = cv2.drawContours(copy, cnts, -1, (0, 0, 0), 1, cv2.LINE_AA)
cv2.imshow('Contours', cont)
cv2.waitKey(0)

mask = np.zeros(cont.shape[:2], dtype="uint8") * 255

# Draw the contours on the mask
cv2.drawContours(mask, cnts, -1, (255, 255, 255), -1)

# remove the contours from the image and show the resulting images
img = cv2.bitwise_and(cont, cont, mask=mask)
cv2.imshow("Mask", img)
cv2.waitKey(0)

for c in cnts:
    x, y, w, h = cv2.boundingRect(c)
    if w > 50 and h > 130:
        new_img = img[y:y + h, x:x + w]
        cv2.imwrite('Cropped.png', new_img)

        cv2.imshow("Cropped", new_img)
        cv2.waitKey(0)

希望将帮助一个以上的用户。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49241490

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档