python-opencv边缘清洗法提取图片轮廓和前景内容

最近在自学游戏开发里面的图形算法,需要提取某些图片的前景内容,替换掉原来的背景。如果是几张图用PS处理一下就行了,但图片量比较打,还是写一个程序比较好。

为了解决这个问题,我接触了opencv这个库,突然觉得这玩意太牛逼了,不光可以处理图片,还内置很多人工智能算法,于是暂时放弃了游戏开发,转战计算机视觉。

学了几天基础知识,刚开始觉得有好多种方法都可以提取图片的前景内容,但用得都不理想。原因有以下2个:

1、教材的案例都太简单了,只是为了更简单的讲解某些概念和某些函数的用法。

2、要想处理实际问题,必须综合灵活运用书本里的知识,书本里的方法都是有各种条件限制的。

话不多说了,下面直接进入正题。

提取前景我找到了以下几种方法:

1)用掩膜进行位运算,这只适合背景颜色单一的使用场景

2)使用grabcut,但需要对图像输入用户交互参数

3)边缘提取,边缘好提取,但图片颜色复杂的话,轮廓不好提取。

4)轮廓检测+洪水填充法,图片轮廓清晰且背景颜色简单好提取,当然复杂的也可以提取出来,但轮廓必须有完整的闭合区域。

5)使用HSV颜色空间颜色区域提取的方法,提取出前景或者背景。这种方法只局限于背景颜色与前景颜色完全隔离的情况下使用,当前景中包含了背景的颜色,这种方法就不好用了。

注意:有的看着颜色单一的背景颜色,其实并不单一,为了增加亮度和良好的视觉效果,即使单纯灰色背景都有几千种,必须在RGB颜色空间下,颜色有1600多万种。

下面介绍一下我自己的方法:

第1步:用canny函数得到最佳边缘

import cv2
IMAGE_NAME = "bird.png"
SAVE_IMAGE_NAME = "canny_"+IMAGE_NAME
img = cv2.imread(IMAGE_NAME)
img2gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
c_canny_img = cv2.Canny(img2gray,50,150)
cv2.imshow('mask',c_canny_img)
k = cv2.waitKey(500) & 0xFF
if k == 27:
   cv2.destroyAllWindows()

        

 第2步:对边缘像素周围的像素用进行迭代像素填充

  实现思路:

   定义一个3X3或者5X5的卷积核,遍历这张边缘图片的每一个像素,当遇到像素点为白色(255,255,255)时,对它周围的像素全部置成白色。有可能第一步效果并不理想,不过没关系,多迭代几次就好了。

代码如下:

# -*- coding: utf-8 -*-
import cv2
import numpy as np

img = cv2.imread('second_bird.png')
rows,cols,ch = img.shape
SIZE = 3 #卷积核大小
P = int(SIZE/2)
BLACK = [0,0,0]
WHITE = [255,255,255]
BEGIN = False
BP = []

for row in range(P,rows-P,1):
    for col in range(P,cols-P,1):
        #print(img[row,col])
        if (img[row, col] == WHITE).all():
            kernal = []
            for i in range(row-P,row+P+1,1):
                for j in range(col-P,col+P+1,1):
                    kernal.append(img[i,j])
                    if (img[i,j] == BLACK).all():
                        #print(i,j)
                        BP.append([i,j])

print(len(BP))
uniqueBP = np.array(list(set([tuple(c) for c in BP])))
print(len(uniqueBP))

for x,y in uniqueBP:
    img[x,y] = WHITE
cv2.imshow('img',img)
cv2.imwrite('second_bird.png',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 效果如下:

其实到这一步已经差不多了,前景图片中间有些小黑点,两种方法解决:

1)用上述的方法再迭代一次,缺陷是如果用5*5的核的话,边缘可能可能会扩大4个像素。

2)运用形态学的方法进行腐蚀膨胀一下。

第3步:用掩膜位运算提取白色区域的内容。

代码如下:

# -*- coding:utf-8 -*-
import cv2
img = cv2.imread('bird.png')
img2 = cv2.imread('second_bird.png')

img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
print(img2gray.shape)
mask = cv2.bitwise_and(img,img,mask=img2gray)
cv2.imshow('mask',mask)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果如下:

最后再说明2点:

1)上述程序我分别用了3个程序文件来实现,只是为了快速调试,后期我会把完整代码贴出来

2)最终结果有些瑕疵,但那都不是问题,用形态学简单处理一下就OK

 

  • 18
    点赞
  • 143
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值