胶囊质量检测
#功能:胶囊缺陷识别
import cv2
import numpy as np
import os
def empty_detection(img_path, img_file, img, img_gray):
# 先模糊,在做二值化
blured = cv2.GaussianBlur(img_gray, (3, 3), 0)
# 二值化
t, img_bin = cv2.threshold(blured, 210, 255, cv2.THRESH_BINARY)
# cv2.imshow('img_binary',img_bin)
# 查找轮廓
image, cnts, hie = cv2.findContours(img_bin,
cv2.RETR_CCOMP, # 两层轮廓
cv2.CHAIN_APPROX_NONE) # 保存所有坐标点
new_cnts = []
# 轮廓过滤
for i in range(len(cnts)):
cir_len = cv2.arcLength(cnts[i], True)
# print('轮廓:{},周长:{}'.format(i,cir_len))
if cir_len >= 1000:
new_cnts.append(cnts[i])
# 绘制轮廓周长大于1000的轮廓
img_cnt = cv2.drawContours(img,
new_cnts,
-1,
(0, 0, 255),
2)
# cv2.imshow('img_cnt',img_cnt)
if len(new_cnts) == 1:
print(img_path, ':', '空胶囊')
# 移动文件
new_path = os.path.join('capsules/empty', img_file)
os.rename(img_path, new_path)
print('文件移动成功:{}-->{}'.format(img_path, new_path))
return True
else:
return False
def bub_detection(img_path, img_file, img, img_gray):
blured = cv2.GaussianBlur(img_gray, (3, 3), 0)
# t,img_bin = cv2.threshold(img_gray,180,255,cv2.THRESH_BINARY)
# cv2.imshow('img_bin',img_bin)
img_canny = cv2.Canny(blured, 60, 240)
# cv2.imshow('img_canny',img_canny)
# 提取轮廓
image, cnts, hie = cv2.findContours(img_canny,
cv2.RETR_CCOMP,
cv2.CHAIN_APPROX_NONE)
new_cnts = []
# 轮廓过滤
for i in range(len(cnts)):
cir_len = cv2.arcLength(cnts[i], True) # 周长
area = cv2.contourArea(cnts[i]) # 面积
if area >= 10000 or cir_len > 900 or area < 5:
continue
if hie[0][i][3] != -1: # 有父轮廓
new_cnts.append(cnts[i])
# 将找到的气泡轮廓绘制
img_cnt = cv2.drawContours(img,
new_cnts,
-1,
(0, 0, 255),
1)
# cv2.imshow('img_cnt',img_cnt)
# 移动目录
if len(new_cnts) > 0:
print(img_path, ':', '黑点气泡瑕疵')
new_path = os.path.join('capsules/bub', img_file)
os.rename(img_path, new_path)
print('文件移动成功:{}-->{}'.format(img_path, new_path))
return True
else:
return False
def balance_detection(img_path, img_file, img, img_gray):
# 要找到胶囊的轮廓 :面积排第二
blured = cv2.GaussianBlur(img_gray, (5, 5), 0)
# 膨胀
kenel = np.ones((5, 5), np.uint8)
dilate = cv2.dilate(blured, kenel)
canny = cv2.Canny(dilate, 60, 200)
# cv2.imshow('canny',canny)
# 提取轮廓
image, cnts, hie = cv2.findContours(canny,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_NONE)
# print(len(cnts))
# print('------')
new_cnts = []
cnts = np.array(cnts)
# 轮廓过滤
if len(cnts) > 0:
for c in cnts:
area = cv2.contourArea(c) # 面积
cir_len = cv2.arcLength(c, True)
# print('area:{},arclength:{}'.format(area,cir_len))
# 注意缩进
if cir_len >= 1000:
new_cnts.append(c)
new_cnts = sorted(new_cnts,
key=cv2.contourArea,
reverse=True)
# 取出面积第二大的
new_cnts = new_cnts[1:2]
# print(new_cnts)
# print('----')
img_cnt = cv2.drawContours(img,
new_cnts,
-1,
(0, 0, 255),
2)
cv2.imshow('img_cnt', img_cnt)
# 求药丸轮廓边界
max_x = new_cnts[0][0][0][0]
max_y = new_cnts[0][0][0][1]
min_x = max_x
min_y = max_y
for cnt in new_cnts[0]:
if cnt[0][0] >= max_x: # 轮廓点的x左边比最大还大
max_x = cnt[0][0]
if cnt[0][0] < min_x:
min_x = cnt[0][0]
if cnt[0][1] >= max_y:
max_y = cnt[0][1]
if cnt[0][1] < min_y:
min_y = cnt[0][1]
# 绘制边界
red = (0, 0, 255)
# cv2.line(img, (min_x, min_y), (max_x, min_y), red, 2)
# cv2.line(img, (max_x, min_y), (max_x, max_y), red, 2)
# cv2.line(img, (max_x, max_y), (min_x, max_y), red, 2)
# cv2.line(img, (min_x, max_y), (min_x, min_y), red, 2)
# 水平中线
center_y = int((min_y + max_y) / 2)
# 上中线
center_up = int((min_y + center_y) / 2)
# 下中线
center_down = int((max_y + center_y) / 2)
# cv2.line(img, (min_x,center_y), (max_x,center_y), red, 2)
cv2.line(img, (min_x, center_up), (max_x, center_up), red, 2)
cv2.line(img, (min_x, center_down), (max_x, center_down), red, 2)
cv2.imshow("img_line", img)
# 求药丸轮廓和上下中线的交点
cross_up = set()
cross_down = set()
for cnt in new_cnts[0]:
x, y = cnt[0][0], cnt[0][1] # 取轮廓上点的x,y坐标
if y == center_up:
cross_up.add((x, y))
if y == center_down:
cross_down.add((x, y))
cross_up = list(cross_up)
cross_down = list(cross_down)
# 在交点处绘制小圆圈
for x, y in cross_up:
cv2.circle(img, (x, y), 8, red, 2)
for x, y in cross_down:
cv2.circle(img, (x, y), 8, red, 2)
cv2.imshow("im_circle", img)
# 计算上中线、下中线长度
len_up = abs(cross_up[0][0] - cross_up[1][0])
len_down = abs(cross_down[0][0] - cross_down[1][0])
print("上中线长度:", len_up)
print("下中线长度:", len_down)
if abs(len_up - len_down) > 8: # 上下中线长度相差超过8
print("大小头:", img_file)
new_path = os.path.join('capsules/imbal', img_file)
os.rename(img_path, new_path)
print('文件移动成功:{}-->{}'.format(img_path, new_path))
return True
else:
return False
if __name__ == '__main__':
# 加载所有待预测的图片
img_dir = 'capsules'
img_fils = os.listdir(img_dir)
# 拼接图片路径
for img_file in img_fils:
img_path = os.path.join(img_dir, img_file)
if os.path.isdir(img_path):
continue
# 拿到每一个图像
img = cv2.imread(img_path)
# 灰度化
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.imshow('img',img)
# cv2.imshow('img_gray',img_gray)
# 空胶囊的检测
is_emptey = False
is_emptey = empty_detection(img_path,
img_file,
img,
img_gray)
# 黑点气泡的胶囊检测
is_bub = False
if not is_emptey:
is_bub = bub_detection(img_path,
img_file,
img,
img_gray)
# 大小头检测
if (not is_emptey) and (not is_bub):
balance_detection(img_path,
img_file,
img,
img_gray)
cv2.waitKey()
cv2.destroyAllWindows()
- 测试代码
import cv2
import numpy as np
import os
def get_file():
dir = './capsules'
list = os.listdir(dir)
file = []
for i in list:
join_dir = os.path.join(dir,i)
if os.path.isdir(join_dir):
continue
file.append(join_dir)
return file
def cap_is_empty(img, img_gray, file_path, file_name=''):
# 模糊
img_gas = cv2.GaussianBlur(img_gray,(5,5),0)
# 二值化
t,img_bin = cv2.threshold(img_gas,210,255,cv2.THRESH_BINARY)
# 轮廓判断
img_find,cont,hie = cv2.findContours(img_bin,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE)
# cv2.imshow('img_gray', img_find)
# 轮廓过滤 根据周长进行判断 只保留周长大于某个值的轮廓
# cont_new = []
# for i in range(len(cont)):
# cir_len = cv2.arcLength(cont[i],True)
# if cir_len >= 1000:
# print(cir_len)
# cont_new.append(cont[i])
# print(len(cont_new))
# # 绘制边沿
# img_cnt = cv2.drawContours(img,cont_new,-1,(0,0,255),2)
# # 查看轮廓
# cv2.imshow('img_gray', img_cnt)
if len(cont) == 1:
# 移动图片
os.rename(file_path,os.path.join('./capsules/empty',file_path[file_path.rfind('/')+1:]))
return True
else:
return False
def cap_is_bub(img, img_gray, file_path):
# 模糊
img_gas = cv2.GaussianBlur(img_gray, (3, 3), 0)
# 二值化
# t, img_bin = cv2.threshold(img_gas, 210, 255, cv2.THRESH_BINARY)
img_candy = cv2.Canny(img_gas,50,240)
# 轮廓判断
img_find,cont,hie = cv2.findContours(img_candy,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE)
# 轮廓过滤 根据周长面积进行判断
cont_new = []
for i in range(len(cont)):
cir_len = cv2.arcLength(cont[i],True)
cir_area = cv2.contourArea(cont[i])
if 5 < cir_area <= 10000 and cir_len <= 2300 and hie[0][i][3] != -1:
cont_new.append(cont[i])
# print('周长%s面积%s,%s' % (cir_len, cir_area,hie[0][i][3]))
# print('--------------')
#
# # 绘制边沿
# img_cnt = cv2.drawContours(img,cont_new,-1,(0,0,255),2)
# cv2.imshow('candy',img_find)
# # 查看轮廓
# cv2.imshow('img_gray', img_cnt)
if len(cont_new) > 0:
# 移动图片
os.rename(file_path,os.path.join('./capsules/bub',file_path[file_path.rfind('/')+1:]))
return True
else:
return False
def cap_is_imbal(img, img_gray, file_path):
# 模糊
img_gas = cv2.GaussianBlur(img_gray, (5, 5), 0)
# 膨胀
kernel = np.ones((3,3),np.uint8)
img_de = cv2.dilate(img_gray,kernel)
#candy
img_candy = cv2.Canny(img_de,50,240)
# 轮廓判断
img_find,cont,hie = cv2.findContours(img_candy,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
# 轮廓过滤 面积排第二
cont_new = []
for i in range(len(cont)):
cir_len = cv2.arcLength(cont[i],True)
cir_area = cv2.contourArea(cont[i])
if cir_len > 900:
cont_new.append(cont[i])
# print('周长%s面积%s,%s' % (cir_len, cir_area,hie[0][i][3]))
# print('--------------')
# 排序
cont_new = sorted(cont_new,key=cv2.contourArea,reverse=True)
cont_new = cont_new[1:2]
# 绘制边沿
img_cnt = cv2.drawContours(img,cont_new,-1,(0,0,255),2)
# cv2.imshow('candy',img_find)
max_x = cont_new[0][0][0][0]
max_y = cont_new[0][0][0][1]
min_x = max_x
min_y = max_y
# 寻找x,y最大值和最小值
for i in cont_new[0]:
if i[0][0] >= max_x:
max_x = i[0][0]
if i[0][0] < min_x:
min_x = i[0][0]
if i[0][1] >= max_y:
max_y = i[0][1]
if i[0][1] < min_y:
min_y = i[0][1]
# print(min_x,max_x,min_y,max_y)
brcnt = np.array([[[min_x,min_y]],[[min_x,max_y]],[[max_x,max_y]],[[max_x,min_y]]])
# print(brcnt)
# 绘制边沿
img_cnt = cv2.drawContours(img,[brcnt],-1,(0,0,255),2)
# 绘制线段
yline1 = int(((max_y-min_y)/4)+min_y)
yline2 = int(((max_y-min_y)/4*3)+min_y)
img_cnt = cv2.line(img,(min_x,yline1),(max_x,yline1),(0,0,255),2)
img_cnt = cv2.line(img,(min_x,yline2),(max_x,yline2),(0,0,255),2)
up_line = []
down_line = []
# 求焦点
for i in cont_new[0]:
if i[0][1] == yline1:
up_line.append(i[0][0])
# 画圆
cv2.circle(img, (i[0][0], i[0][1]), 10, (0, 255, 0), 2)
if i[0][1] == yline2:
down_line.append(i[0][0])
# 画圆
cv2.circle(img, (i[0][0], i[0][1]), 10, (0, 255, 0), 2)
up = up_line[0]-up_line[1]
down = down_line[0]-down_line[1]
# print("up %s,down %s all %s"%(up,down,abs(up-down)))
# 查看图片
# cv2.imshow('img_gray', img_cnt)
if abs(up-down) > 10:
# 移动图片
os.rename(file_path,os.path.join('./capsules/imbal',file_path[file_path.rfind('/')+1:]))
return True
else:
return False
if __name__ == '__main__':
# 获取所有文件路径
for file_path in get_file():
img = cv2.imread(file_path)
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 判断是否为空
ie = False
ib = False
ie = cap_is_empty(img,img_gray,file_path)
if ie != True:
# 判断是否有气泡
ib = cap_is_bub(img,img_gray,file_path)
if ie == False and ib == False:
# 判断是否大小头
ii = cap_is_imbal(img,img_gray,file_path)
cv2.waitKey()
cv2.destroyAllWindows()
轨道交叉点检测
# 利用图像技术实现铁轨交叉点检测
import cv2
import numpy as np
import math
# 生成线段上所有点的坐标
def calc_line_points(x1, y1, x2, y2):
# 线段斜率
k = float(y2 - y1) / float(x2 - x1)
# 偏置
b = float(y1) - float(x1) * k
points = []
for x in range(x1, x2 + 1):
y = int(k * x + b) # 计算y
points.append((x, y)) # 将每个点的坐标添加到列表
return points
# 判断两个线段是否存在交点
def cross_point(line1, line2):
is_exist = False # 是否存在交点返回值
x, y = 0, 0 # 交点坐标初始值
x1, y1, x2, y2 = line1 # 取出第一个线段的端点坐标
x3, y3, x4, y4 = line2 # 取出第二个线段的端点坐标
# 排除不可能存在交点的情况
k1 = float(y2 - y1) / float(x2 - x1) # 第一个线段斜率
k2 = float(y4 - y3) / float(x4 - x3) # 第二个线段斜率
if abs(k1 - k2) < 0.3: # 斜率很接近
return False, [0, 0] # 不存在交点
# 如果一条线段最大x值小于另一条最小x值,不可能产生交点
if max(x2, x1) < min(x3, x4):
return False, [0, 0]
if max(x3, x4) < min(x2, x1):
return False, [0, 0]
# 如果一条线段最大y值小于另一条最小y值,不可能产生交点
if max(y2, y1) < min(y3, y4):
return False, [0, 0]
if max(y3, y4) < min(y2, y1):
return False, [0, 0]
# 计算两个线段上所有点的坐标值,比较是否有交点
points_1 = calc_line_points(x1, y1, x2, y2)
points_2 = calc_line_points(x3, y3, x4, y4)
for p1 in points_1:
for p2 in points_2:
x1, y1 = p1
x2, y2 = p2
# 计算两点的距离
dist = math.sqrt((x1-x2)**2 + (y1-y2)**2)
if dist < 4: # 距离非常接近,交点
return True, [x1, y1]
return False, [0, 0]
def cross_detection(img_path):
im = cv2.imread(img_path) # 读取图像
cv2.imshow("im", im)
# 灰度化
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imshow("im_gray", im_gray)
# 对图像进行卷积,加强垂直方向的纹理
flt = np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])
im_conv = cv2.filter2D(im_gray, -1, flt,
borderType=1)
cv2.imshow("im_conv", im_conv)
# 二值化
t, im_bin = cv2.threshold(im_conv, 180, 255,
cv2.THRESH_BINARY)
cv2.imshow("im_bin", im_bin)
# 霍夫变换检测图像中的线段
lines = cv2.HoughLinesP(
im_bin, # 输入图像
1, # 以像素作为距离精度单位
np.pi / 180, # 角度, π/180表示所有可能的角度
1, # 该值越小,检测出的线段越多
minLineLength=70, # 线段最小长度
maxLineGap=20) # 最大间隔距离,小于该值认为属同一个线段
print(type(lines))
print(lines.shape)
# print(lines)
# 在原图上绘制找到的线段
red = (0, 0, 255)
for ln in lines:
x1, y1, x2, y2 = ln[0] # 取出端点坐标
cv2.line(im, (x1, y1), (x2, y2), red, 2)
cv2.imshow("im_lines", im)
lines = lines[:, 0, :]
# 线段两两比较
for x1, y1, x2, y2 in lines:
for x3, y3, x4, y4 in lines:
# 通过函数判断两个线段是否存在交点
is_exist, [x, y] = cross_point(
[x1, y1, x2, y2], [x3, y3, x4, y4])
if is_exist:# 存在交点
cv2.circle(im, (x,y), 5, red, 3)
cv2.imshow("result", im) # 显示结果
cv2.waitKey()
cv2.destroyAllWindows()
if __name__ == "__main__":
cross_detection("rail_1.png")
- 测试代码
import cv2
import numpy as np
# 计算线段上所有的点
def calc_line_points(x1, y1, x2, y2):
k = float(y2-y1)/float(x2-x1)
b = float(y1)-float(x1)*k
point = []
for i in range(x1,x2+1):
point.append([i,int(i*k+b)])
return point
def cross_point(line1, line2):
is_exist = False
x,y = 0,0
x1, y1, x2, y2 = line1
x3, y3, x4, y4 = line2
# 排除斜率过小的情况
k1 = float(y2-y1)/float(x2-x1)
k2 = float(y4-y3)/float(x4-x3)
if abs(k2-k1)<0.3:
return False,[0,0]
# 线段最大值小于另一条线段最小值 不可能有交点
if max(x1,x2) < min(x3,x4):
return False,[0,0]
if max(x3,x4) < min(x1,x2):
return False,[0,0]
# 线段最大值小于另一条线段最小值 不可能有交点
if max(y1,y2) < min(y3,y4):
return False,[0,0]
if max(y3,y4) < min(y1,y2):
return False,[0,0]
point1 = calc_line_points(x1,y1,x2,y2)
point2 = calc_line_points(x3,y3,x4,y4)
for i in point1:
for j in point2:
x1,y1 = i
x2,y2 = j
#计算斜边长度
dict = np.math.sqrt((x1-x2)**2 + (y1-y2)**2)
if dict < 4:
return True,[x1,y1]
return False,[0,0]
def cross_d(img_path):
img = cv2.imread(img_path)
im_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 二值化
# t,img_bin = cv2.threshold(im_gray,170,255,cv2.THRESH_BINARY)
# cv2.imshow('img_bin',img_bin)
# 卷积
fit = np.array([[-1,0,1],
[-2,0,2],
[-1,0,1]])
img_con = cv2.filter2D(im_gray,-1,fit,borderType=1)
# cv2.imshow('im_gray',img_con)
# 二值化
t,img_bin = cv2.threshold(img_con,180,255,cv2.THRESH_BINARY)
# cv2.imshow('img_bin',img_bin)
line = cv2.HoughLinesP(
img_bin,#输入图像
1,#以像素作为距离精度单位
np.pi/180,#角度,pi/180表示所有可能角度
1,#该值越小,检出线段越多
minLineLength=70,#线段最小长度
maxLineGap=20)#最大间隔距离,小于该值认为属于同一个线段
print(type(line))
print(line.shape)
for i in line:
x1,y1,x2,y2 = i[0]
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
line = line[:,0,:]
for x1,y1,x2,y2 in line:
for x3, y3, x4, y4 in line:
# 判断焦点是否存在
is_exist,[x,y] = cross_point([x1,y1,x2,y2],[x3, y3, x4, y4])
if is_exist:
cv2.circle(img,(x,y),10,(0,255,0),2)
cv2.imshow('im',img)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__ == '__main__':
cross_d('./rail_1.png')
最后一次更新于2023-08-28 13:39
0 条评论