2020-10-13基于OpenCV的条形码区域分割

S1:对图像进行读取和显示

使用函数cv2.imread(filepath,flags)读入一副图片
filepath:要读入图片的完整路径
flags:读入图片的标志
cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道
cv2.IMREAD_GRAYSCALE:读入灰度图片
cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道

plt.imshow()函数负责对图像进行处理,并显示其格式,而plt.show()则是将plt.imshow()处理后的函数显示出来。

import cv2 as cv
from matplotlib import pyplot as plt
# 对测试数据进行读取和显示
image = cv.imread("C:/Users/tzting/Desktop/BarcodesTutorial-master/BarcodesTutorial-master/img/barcodes.jpg", cv.IMREAD_GRAYSCALE)
plt.imshow(image,interpolation='nearest',cmap='Greys_r')# interpolation代表的是插值运算,'nearest'只是选取了其中的一种插值方式。cmap表示绘图时的样式,这里选择的是Greys_r主题。
plt.title("test_image")
plt.show()

彩色图像:


image.png

读入的直接是灰度图像时:


teat_image.png

问题来了:
输入的图像红色的,而在python中为蓝色,为什么呢?
然后我又用cv.imshow()来验证

import cv2 as cv
# 对测试数据进行读取和显示
image = cv.imread("C:/Users/tzt/Desktop/BarcodesTutorial-master/BarcodesTutorial-master/img/barcodes.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", image)

cv.waitKey(0)
cv.destroyAllWindows()

发现输出结果为红色

input image.png

出现上面这个原因是因为 opencv 的接口使用BGR模式,而 matplotlib.pyplot 接口使用的是RGB模式
image.png

最后修改完的代码如上图所示,这是中间的小插曲,让我们继续!
image.png

S2:二值化处理

通过阈值的设定来提取出我们感兴趣的部分。使用黑帽运算符,我们可以增加较暗的图像元素。首先使用简单的全局阈值安全地对图像进行二值化处理。黑帽运算符使我们可以使用非常低的阈值,而不必过多地关注噪声。

1、黑帽

dst = cv2.morphologyEx(src,op,kernel,anchor,iterations,borderType,borderValue)
例子:image = cv.morphologyEx(image,cv.MORPH_BLACKHAT,kernel,anchor=(1,0))
src: 输入图像对象矩阵,为二值化图像
op: 形态学操作类型
cv2.MORPH_OPEN 开运算:先进行腐蚀操作,后进行膨胀操作,主要用来去除一些较亮的部分,即先腐蚀掉不要的部分,再进行膨胀。
cv2.MORPH_CLOSE 闭运算:先进行膨胀操作,后进行腐蚀操作,主要用来去除一些较暗的部分。腐蚀高亮
cv2.MORPH_GRADIENT 形态梯度:膨胀运算结果减去腐蚀运算结果,可以拿到轮廓信息。
cv2.MORPH_TOPHAT 顶帽运算:原图像减去开运算结果。
cv2.MORPH_BLACKHAT 底帽运算:原图像减去开运算结果。
kernel:进行腐蚀操作的核,可以通过函数getStructuringElement()获得
anchor:锚点,默认为(-1,-1)
iterations:腐蚀操作的次数,默认为1
borderType: 边界种类
borderValue:边界值
参考1:https://www.cnblogs.com/silence-cho/p/11069903.html
2:https://www.jianshu.com/p/fc07d3065cf1

2、图像预处理

threshold()函数原型如下:
double cv::threshold ( InputArray src, OutputArray dst, double thresh, double maxval, int type )
例子:thresh, image = cv.threshold(image, 10, 255, cv.THRESH_BINARY)
InputArray src: 输入图像,可以是Mat类型,图像必须为单通道8位或32位浮点型图像
OutputArray dst: 输出图像,与输入图像尺寸和类型相同
double thresh: 设定的阈值
double maxval: 使用THRESH_BINARY和THRESH_BINARY_INV类型的最大值
int type: 阈值化类型
参考:https://blog.csdn.net/keith_bb/article/details/54617625?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param

# 重新定义下图像的大小
scale = 800.0/image.shape[1]
image = cv.resize(image,(int(image.shape[1]*scale),int(image.shape[0]*scale)))
# 黑帽
kernel = np.ones((1,3),np.uint8)
image = cv.morphologyEx(image,cv.MORPH_BLACKHAT,kernel,anchor=(1,0))
# 阈值处理
thresh, image = cv.threshold(image, 10, 255, cv.THRESH_BINARY)
cv.imshow("then_image",image)

result:


黑帽加阈值处理结果

先腐蚀再膨胀 其实就是开操作,先膨胀再腐蚀 其实就是闭操作,上面已经定义过!

# operazioni  morfologiche 形态运算
kernel = np.ones((1, 5), np.uint8)
image = cv.morphologyEx(image, cv.MORPH_DILATE, kernel, anchor=(-1,-1), iterations=2)  # dilatazione膨胀求局部最大值,腐蚀求局部最小值
image = cv.morphologyEx(image, cv.MORPH_CLOSE, kernel, anchor=(-1,-1), iterations=2)  # chiusura关闭
cv.imshow("dilate_close_demo",image)
kernel = np.ones((21, 35), np.uint8)
image = cv.morphologyEx(image, cv.MORPH_OPEN, kernel, iterations=1)  # 最后的预处理步骤是应用具有很大内核的开运算符,以删除太少而无法适合条形码形状的元素。
cv.imshow("last_demo",image)
膨胀+关闭操作
最后使用35*21内核闭处理后的图像

S3:检索带有坐标和尺寸的条形码矩形

opencv中通过使用findContours函数,简单几个的步骤就可以检测出物体的轮廓
原型
findContours( InputOutputArray image, OutputArrayOfArrays contours,OutputArray hierarchy, int mode, int method, Point offset=Point());
第一个参数:image,单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;

第二个参数:contours,定义为“vector<vector<Point>> contours”,是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓有多少轮廓,向量contours就有多少元素。

第三个参数:hierarchy,定义为“vector<Vec4i> hierarchy”,先来看一下Vec4i的定义: typedef Vec<int, 4> Vec4i;

       Vec4i是Vec<int,4>的别名,定义了一个“向量内每一个元素包含了4个int型变量”的向量。

       所以从定义上看,hierarchy也是一个向量,向量内每个元素保存了一个包含4个int整型的数组。

       向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。

       hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第

    i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个

    轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为

    默认值-1。

第四个参数:int型的mode,定义轮廓的检索模式:

       取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略



       取值二:CV_RETR_LIST   检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关

              系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,

              所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到



       取值三:CV_RETR_CCOMP  检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围

              内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层



       取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内

               层轮廓还可以继续包含内嵌轮廓。

第五个参数:int型的method,定义轮廓的近似方法:

       取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内



       取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours

               向量内,拐点与拐点之间直线段上的信息点不予保留



       取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

第六个参数:Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,并且Point还可以是负值!
参考:https://blog.csdn.net/dcrmg/article/details/51987348#
在上面的代码中,我使用提取的矩形绘制它们,并将其覆盖在原始图像上

# estrazione dei componenti connessi 提取连接组件
image,contours , hierarchy= cv.findContours(image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)

unscale = 1.0 / scale
if contours != None:
    for contour in contours:

        # se l'area non è grande a sufficienza la salto如果面积不够大,则跳
        if cv.contourArea(contour) <= 2000:
            continue

        # estraggo il rettangolo di area minima (in formato (centro_x, centro_y), (width, height), angolo)我提取最小面积的矩形(格式为(centro_x,centro_y),(宽度,高度),角)
        rect = cv.minAreaRect(contour)
        # l'effetto della riscalatura iniziale deve essere eliminato dalle coordinate rilevate必须从检测到的坐标中消除初始重新缩放的影响
        rect = \
            ((int(rect[0][0] * unscale), int(rect[0][1] * unscale)), \
             (int(rect[1][0] * unscale), int(rect[1][1] * unscale)), \
             rect[2])

        # disegno il tutto sull'immagine originale我将所有内容绘制在原始图像上
        box = np.int0(cv.boxPoints(rect))
        cv.drawContours(image_out, [box], 0, (0, 255, 0), thickness=2)

plt.imshow(image_out)
# scrittura dell' immagine finale写最后的形象
cv.imwrite(r'C:/Users/tzt/Desktop/out.png', image_out)

最后运行结果:


image.png

后面学的有点仓促,之后在研究!整篇论文是基于https://blog.csdn.net/qq_42722197/article/details/108971078上研究的,谢谢小白学视觉,感觉是个良心公众号哈哈哈!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352