代码【自用暂存】
import os
from PIL import Image
import cv2
import cv2 as cv
import numpy as np
from nsingle_numeracy_2 import zhizhen
from matplotlib import pyplot as plt
'''#图像预处理'''
import numpy as np
import cv2
def tiqu(HSV_img,circles,n ):
low_hsv = np.array([150, 43, 46])
high_hsv = np.array([180, 255, 255])
# 使用opencv的inRange函数提取颜色
mask_Red1 = cv2.inRange(HSV_img, lowerb=low_hsv, upperb=high_hsv)
# Red = cv2.bitwise_and(target, target, mask=mask)
# cv2.imshow("Red1", mask_Red1)
# cv2.waitKey(0)
low_hsv = np.array([0, 43, 46])
high_hsv = np.array([10, 255, 255])
# 使用opencv的inRange函数提取颜色
mask_Red2 = cv2.inRange(HSV_img, lowerb=low_hsv, upperb=high_hsv)
# cv2.imshow("Red2", mask_Red2)
# cv2.waitKey(0)
# Black = cv2.bitwise_and(target, target, mask=mask)
maskRed = mask_Red1 + mask_Red2
maskRed = cv2.medianBlur(maskRed, 11) # 进行中值模糊,去噪点
# 腐蚀膨胀
# maskRed = cv2.erode(maskRed, None, iterations=2)
# maskRed = cv2.dilate(maskRed, None, iterations=1)
# # 获取尺寸
# h, w, _ = img.shape
# # 建立一个与图像尺寸相同的全零数组
# npim = np.zeros((h, w, 3), dtype=np.int)
# # 将图像3个通道相加赋值给空数组
# npim[:] = img[:, :, 0] + img[:, :, 1] + img[:, :, 2]
# 统计白色像素个数
# print("白色像素点:", len(maskRed[maskRed == 255]))
# if len(maskRed[maskRed == 255]) < 400:
# # # 统计黑色像素个数
# #
# # print(“黑色像素 % s个” % len(npim[npim == 0]))
# maskRed = cv2.erode(maskRed, None, iterations=2)
# maskRed = cv2.dilate(maskRed, None, iterations=1)
# else:
maskRed = cv2.erode(maskRed, None, iterations=n)
maskRed = cv2.dilate(maskRed, None, iterations=1)
cv2.imshow("thresh", maskRed)
cv2.waitKey(0)
cannyimage = cv2.Canny(maskRed, 50, 100) # 边缘检测#调用Canny函数,指定最大和最小阈值,其中apertureSize默认为3。
cv2.imshow("Red", maskRed)
cv2.imshow("cannyimage", cannyimage)
cv2.waitKey(0)
circles = cv2.HoughCircles(cannyimage, cv2.HOUGH_GRADIENT, 1, 300, param1=100, param2=10, minRadius=10,
maxRadius=100)
n=n-1
return maskRed,circles,n,cannyimage
def tiqublack(img,circles,n ):
# 使用opencv的inRange函数提取颜色
low_hsv = np.array([0, 0, 0])
high_hsv = np.array([180, 255, 46])
# 使用opencv的inRange函数提取颜色
mask_Black = cv2.inRange(img, lowerb=low_hsv, upperb=high_hsv)
mask = cv2.medianBlur(mask_Black, 9) # 进行中值模糊,去噪点
# 腐蚀膨胀
mask = cv2.erode(mask, None, iterations=n)
mask = cv2.dilate(mask, None, iterations=1)
cv2.imshow("thresh", mask)
cv2.waitKey(0)
cannyimage = cv2.Canny(mask, 50, 100) # 边缘检测#调用Canny函数,指定最大和最小阈值,其中apertureSize默认为3。
# cv2.imshow("Black", mask_Black)
circles = cv2.HoughCircles(cannyimage, cv2.HOUGH_GRADIENT, 1, 300, param1=100, param2=10, minRadius=3,
maxRadius=100)
n=n+1
return mask,circles,n,cannyimage
def gray_cvt(inputimagepath, graywindowname, outimagepath):
gray_cvt_image = cv2.cvtColor(inputimagepath, cv2.COLOR_RGB2GRAY) # 灰度化
cv2.namedWindow(graywindowname) # 控制显示图片窗口的名字
cv2.imshow(graywindowname, gray_cvt_image) # 显示灰度化后的图像
cv2.imwrite(outimagepath, gray_cvt_image) # 保存当前灰度值处理过后的文件
# cv2.waitKey() # 等待操作
# cv2.destroyAllWindows() # 关闭显示图像的窗口
def dushu(x1,y1,x2,y2):
if x1 == x2:
return 90
if y1 == y2:
return 180
k = -(y2 - y1) / (x2 - x1)
# 求反正切,再将得到的弧度转换为度
result = np.arctan(k) * 57.29577
# 234象限
if x1 > x2 and y1 > y2:
result += 180
elif x1 > x2 and y1 < y2:
result += 180
elif x1 < x2 and y1 < y2:
result += 360
if 54<result<=90 :
n=0
elif 18<result<=54 :
n = 1
elif 0<=result<=18 or 360>=result>342:
n = 2
elif 306<result<=342 :
n = 3
elif 270<result<=306 :
n = 4
elif 234<result<=270 :
n = 5
elif 198<result<=234 :
n = 6
elif 162<result<=198 :
n = 7
elif 126<result<=162 :
n = 8
elif 90<result<=126:
n = 9
else:
print("读数发生错误!")
print("直线倾斜角度为:" + str(result) + "度,读数为", n) # 得到倾斜角度
return int( n),result
def zhizhen(img,color):
global cons_img
graywindowname = 'gray_cvt'
outimagepath = "gray_cvt.jpg"
gray_cvt(img, graywindowname, outimagepath)#自带函数进行灰度化
img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
if color == 'b':
# 提取黑色指针
circles = None
k =2
while circles is None:
mask, circles, k, cannyimage = tiqublack(img, circles, k)
if circles is not None:
break
if color == 'r':
# 提取红色指针
circles = None
k =7
while circles is None:
mask, circles,k,cannyimage = tiqu(img, circles, k)
if circles is not None :
break
# 根据检测到圆的信息,画出每一个圆
maskpointpath = "maskpoint,jpg"
cv2.imshow("cannyimage", cannyimage)
cv2.waitKey(0)
#检测指针圆心
#circles = cv2.HoughCircles(mask_Black, cv2.HOUGH_GRADIENT, 1, 100, param1=100, param2=1, minRadius=10, maxRadius=15)
##原代码circles = cv2.HoughCircles(cannyimage, cv2.HOUGH_GRADIENT, 1, 300, param1=100, param2=2, minRadius=10, maxRadius=100)
# 根据检测到圆的信息,画出每一个圆
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# draw the outer circle
cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2)
# draw the center of the circle
cv2.circle(img, (i[0], i[1]), 1, (0, 0, 255), 3)
cv2.imshow('circle', img)
# print(len(circles[0, :]))
# # Shi-Tomasi 算法是Harris 算法的改进,角点算法识别指针顶端
cons = []
#corners = cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance, mask, blockSize, gradientSize[,corners[, useHarrisDetector[, k]]])
con = cv2.goodFeaturesToTrack(mask ,1, 0.9, 10)
if con is not None and len(con) > 0:
for x, y in np.float32(con).reshape(-1, 2):
cons.append((x, y))
cons_img = cv2.circle(img, (int(x), int(y)), 1, (0, 0, 255))
# 输出角点
print(cons, i[0], i[1])
cv2.imshow('cons_img ', cons_img)
cv2.waitKey(0)
linepic = cv2.line(img, (int(cons[0][0]), int(cons[0][1])), (int(i[0]), int(i[1])), (0, 0, 255))
# if i[0] is int:
n, ang = dushu(i[0], i[1], cons[0][0], cons[0][1])
# print(n)
# else:
# n, ang = dushu(int(i[0]),int( i[1]), int(cons[0][0]), int(cons[0][1]))
#linepic = cv2.line(img, (cons[0][0], cons[0][1]), (i[0], i[1]), (0, 0, 255))
cv2.imshow('linepic', linepic)
cv2.waitKey(0)
return (n)
# 圆形头像
# def circle(img_path):
# # path_name = os.path.dirname(img_path)
# # cir_file_name = 'cir_img.png'
# # cir_path = path_name + '/' + cir_file_name
# print("mask来了")
# ima = Image.open(img_path).convert("RGBA")
# size = ima.size
# print(size)
# # 因为是要圆形,所以需要正方形的图片
# r2 = min(size[0], size[1])
# if size[0] != size[1]:
# ima = ima.resize((r2, r2), Image.ANTIALIAS)
# # 最后生成圆的半径
# r3 = int(r2 / 2)
# imb = Image.new('RGBA', (r3 * 2, r3 * 2), (255, 255, 255, 0))
# pima = ima.load() # 像素的访问对象
# pimb = imb.load()
# r = float(r2 / 2) # 圆心横坐标
#
# for i in range(r2):
# for j in range(r2):
# lx = abs(i - r) # 到圆心距离的横坐标
# ly = abs(j - r) # 到圆心距离的纵坐标
# l = (pow(lx, 2) + pow(ly, 2)) ** 0.5 # 三角函数 半径
# if l < r3:
# pimb[i - (r - r3), j - (r - r3)] = pima[i, j]
# imb.save("1mask.jpg")
def dividing(img):
src = img # 读取图片
ROI = np.zeros(src.shape, np.uint8) # 创建与原图同尺寸的空numpy数组,用来保存ROI信息
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) # 灰度化
#ret, binary = cv.threshold(gray,0, 255, cv.THRESH_BINARY_INV | cv.THRESH_TRIANGLE) # 自适应二值化
binary= cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,19,10)
#binary= cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,19,19)
cv2.imshow("RO", binary )
cv2.waitKey(0)
#circles = cv2.HoughCircles(binary, cv2.HOUGH_GRADIENT, 1, 50, param1=100, param2=21, minRadius=20, maxRadius=40)
circles = cv2.HoughCircles(binary, cv2.HOUGH_GRADIENT, 1, 50, param1=100, param2=21, minRadius=20, maxRadius=40)
# 根据检测到圆的信息,画出每一个圆
circles = np.uint16(np.around(circles))
n=0
x = [[] for i in range(8)]
for i in circles[0, :]:
if n<8:
x[n].append(i[0])
x[n].append(i[1])
x[n].append(i[2])#存储圆的信息
n = n + 1
else :
break
# # draw the outer circle
# cv2.circle(src, (i[0], i[1]), i[2]+1, (0, 255, 0), 2)
# # draw the center of the circle
# cv2.circle(src, (i[0], i[1]), 1, (0, 0, 255), 3)
# cv2.imshow('circle', src)
# cv2.waitKey(0)
# print(x)
x=np.array(x)
x=x[x[:,0].argsort()]#根据图上位置排序表盘
# print('new',x)
n=0
ang = [0, 0, 0, 0, 0, 0, 0, 0]
for i in range(len(x)):
# draw the outer circle
circle = np.zeros(ROI.shape[0:2], dtype="uint8") # 创建圆
maskcircle = cv2.circle(circle,(x[i][0], x[i][1]), x[i][2],255, -1) # 修改填充白色
#
# 添加白色背景
mask = np.zeros(ROI.shape[0:2], dtype="uint8") # 创建矩形
mask =cv2.rectangle(mask, (x[i][0]- x[i][2]-1, x[i][1]- x[i][2]-1), (x[i][0]+x[i][2]+1, x[i][1]+ x[i][2]+1),255, -1)
mask = cv2.add(src, np.zeros(np.shape(src), dtype=np.uint8), mask=mask)
# cv2.imshow('result.jpg', mask)
# cv2.waitKey(0)
bg = np.ones_like(img, np.uint8) * 255
cv2.bitwise_not(bg, bg, mask=maskcircle) # bg的多边形区域为0,背景区域为255
mask=mask+bg
# rows, cols, channel = mask.shape
# # 创建一张4通道的新图片,包含透明通道,初始化是透明的
# img_new = np.zeros((rows, cols, 4), np.uint8)
# img_new[:, :, 0:3] = mask[:, :, 0:3]
# # 创建一张单通道的图片,设置最大内接圆为不透明,注意圆心的坐标设置,cols是x坐标,rows是y坐标
# img_circle = np.zeros((rows, cols, 1), np.uint8)
# img_circle[:, :, :] = 0 # 设置为全透明
# img_circle = cv2.circle(img_circle, (cols / 2, rows / 2), min(rows, cols) / 2, (255), -1) # 设置最大内接圆为不透明
# # 图片融合
# mask[:, :, 3] = img_circle[:, :, 0]
# # 保存图片
# cv2.imwrite(mask + ".png", mask)
# # cv2.imencode('.jpg', img)[1].tofile('./9.jpg') # 保存到另外的位置
# mask = src[x[i][1]- x[i][2]-1:x[i][1]+ x[i][2]+1, x[i][0]- x[i][2]-1:x[i][0]+x[i][2]+1 ] # 裁剪矩形坐标为[y0:y1, x0:x1]
# cv2.imwrite("1mask.jpg",mask)
# circle("1mask.jpg")
# mask =cv2.imread("1mask.jpg")
# cv2.imwrite("1mask.jpg",mask)
# # 从中心开始 剪切 200*200的图片mask
# print( src.size[0], src.size[1])
# half_the_width = src.size[0] / 2
# half_the_height = src.size[1] / 2
# mask = img.crop(
# (
# half_the_width - x[i][2]/2,
# half_the_height - x[i][2]/2,
# half_the_width + x[i][2]/2,
# half_the_height + x[i][2]/2
# )
# )
# mask = mask.crop((x[i][0], x[i][1], x[i][2], x[i][2]))
cv2.imshow('result.jpg', mask)
cv2.waitKey(0)
# cv2.circle(ROI,(x[i][0], x[i][1]), x[i][2]+2, (255, 255, 255),-1)#注:必须为实心
# imgroi = ROI & src
# cv2.imshow("ROI", imgroi)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# cv2.imwrite("ROI.jpg")
if n>=0and n<=3 :
ang[n]=zhizhen(mask,'b')
elif 3<n<8:
ang[n]=zhizhen(mask,'r')
n=n+1
print("黑色指针部分水表读数为:", ang[2], ang[0], ang[1], ang[3])
print("红色指针部分水表读数为:", ang[4], ang[6], ang[7], ang[5])
if __name__ == '__main__':
#img = "train5.jpeg"
img = "1second_template.jpg"
#img = "train6.jpeg"
#img = "train7.jpeg"
img = cv2.imread(img)
#第一步:选出ROI区域,分割成单个圆盘
dividing(img)