需求:以上图像是金属/丝状物/金属三层夹心结构,希望通过opencv计算出丝状物在两金属所形成带隙中的面积占比。
拟解决思路:二值分割 + 滤波(形态学)+ 轮廓提取,路线如下图。
以下是具体代码
import cv2
import tkinter
import numpy as np
from matplotlib import pyplot as plt
#定义线性增强函数,为增强区间
def linear_threshold(Image,h,w,x1,x2,z2,z1 = 0,z3 = 0):
for i in range(0, h):
for j in range(0, w):
tmp = Image[i, j]
if tmp < x1:
Image[i, j] = z1
elif tmp >= x1 and tmp < x2:
Image[i, j] = z2
else:
Image[i, j] = z3
return Image
#轮廓面积计算函数
def areaCal(contour):
area = 0
for i in range(len(contour)):
area += cv2.contourArea(contour[i])
return area
接下来就是主函数了
if __name__ == '__main__':
#读入图片
img = cv2.imread('C-1-P.tif',0)
#设置掩模,将处理图像聚焦到夹层处
mask = np.zeros(img.shape[:2],np.uint8)
#掩模尺寸
mask[800:1100,100:2400] = 255
masked_img = cv2.bitwise_and(img,img,mask = mask)
# 灰度直方图
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])
#突出前景,增强图像特征,阈值<26,200>是根据直方图像粗略估计而得,由于直方图是单峰(图片略渣),暂不知解决方案,有待修改。
threshold_image = linear_threshold(masked_img,1920,2560,26,200,255)
#中值滤波
median1 = cv2.medianBlur(threshold_image,5)
接下来就是利用matplotlib生成所有图像
# 生成图像
plt.subplot(2,2,1),plt.imshow(img,'gray')
plt.subplot(2,2,2),plt.imshow(threshold_image,'gray')
plt.subplot(2, 2, 3), plt.plot(hist_mask)
plt.subplot(2, 2, 4), plt.imshow(median1, 'gray')
plt.show()
最后就是面积计算,第一步生成轮廓图像,第二步利用轮廓面积计算函数将所有轮廓累加求和。
Image = np.zeros((1920, 2560), np.uint8)
#cv2.findContours()有三个参数:1、输入图像;2、轮廓;3、层析结构。返回值有三个,其中第二个返回值是python列表,存储所有轮廓,且每一个轮廓都是Numpy数组,包含对象边界点(x,y)坐标。其余两返回值可参考openCV中文文档。
image,contours,hierarchv = cv2.findContours(median1,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
color = cv2.cvtColor(Image,cv2.COLOR_GRAY2BGR)
#将轮廓在Image中生成
Image = cv2.drawContours(color,contours,-1,(0,0,255),1)
plt.imshow(Image)
plt.show()
#得到轮廓面积并打印
print(areaCal(contours))
**总结与不足:
由于图像灰度比较集中,仅有一个峰,不知道该如何确定最佳阈值,需要改进,也希望Homie们能提供宝贵意见,感激不尽。**