import cv2
import numpy as np
import os
img_path = "1.JPG" # 图像路径
img_color = cv2.imread(img_path) # 读取彩色图像
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) # 读取图像灰度图
t = img_path.split(".")[0] # 获取到图像的名称,用来给文件夹命名
dir_name = "pic" + str(t) # 文件夹名称
if not os.path.exists(dir_name): # 判断文件夹pic是否存在,创建pic文件夹用来存放图像
os.mkdir(dir_name) # 如果不存在就创建文件夹
Gaussian_img = cv2.GaussianBlur(img, (3, 3), sigmaX=1) # 高斯滤波
contour_list = [] # 定义一个列表,存放需要提取的轮廓,即筛选后的轮廓
for i in range(210, 250, 10):
# 无法完全检测的原因是不同图像适用的阈值不同,因此增加对阈值的迭代
ret, threshold = cv2.threshold(Gaussian_img, i, 255,
cv2.THRESH_BINARY) # 二值化,设置阈值为i,
cv2.imwrite(dir_name + "/threshold.jpg", threshold) # 保存图像
kernel = np.ones((5, 5)) # 定义腐蚀的核
img_erode = cv2.erode(threshold, kernel) # 进行腐蚀操作 去栅格线 腐蚀:让白色变少,黑色变多,用于去毛刺
cv2.imwrite(dir_name + "/img_erode.jpg", img_erode) # 保存图像
kernel2 = np.ones((15, 15)) # 定义膨胀的核
img_dilate = cv2.dilate(img_erode, kernel2) # 膨胀:让黑色变少,白色变多,用于让多个白块连接在一起,形成联通域
cv2.imwrite(dir_name + "/img_dilate.jpg", img_dilate) # 保存图像
contours, hir = cv2.findContours(img_dilate, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # 对膨胀后的图像进行轮廓提取
img_color_copy = img_color.copy() # 复制彩色图像
cv2.drawContours(img_color_copy, contours, -1, (0, 255, 0), 2) # 绘制所有轮廓
cv2.imwrite(dir_name + "/img_color_all_c.jpg", img_color_copy) # 保存图像
for c in contours: # 对轮廓进行筛选
area = cv2.contourArea(c) # 求轮廓面积
if 600000 < area < 1000000: # 面积条件
contour_list.append(c) # 将满足条件的轮廓加入列表
else:
continue
if len(contour_list) >= 22: # 增加对轮廓个数的一个判断,如果达到了个数就结束迭代
break
if len(contour_list) >= 22: # 增加对轮廓个数的一个判断,如果达到了个数就继续操作,否则直接结束
img_color_copy2 = img_color.copy() # 复制彩色图像
cv2.drawContours(img_color_copy2, contour_list, -1, (0, 0, 255), 2) # 绘制筛选后的轮廓
cv2.imwrite(dir_name + "/img_color_loc_c.jpg", img_color_copy2) # 保存图像
# 如下多行代码是使用近似轮廓对轮廓进行标号
img_color_copy5 = img_color.copy() # 复制彩色图像
approx = [] # 近似轮廓的顶点坐标
n = 1
for c in contour_list:
while True:
a = 0.1 # a用来调整精度
epsilon = a * cv2.arcLength(c, True) # 近似轮廓的精度 参数为轮廓、是否闭合 精度越小越精确
approx = cv2.approxPolyDP(c, epsilon, True) # 近似轮廓 参数为轮廓、精度、否闭合 返回值为近似轮廓顶点坐标
if len(approx) == 4: # 判断顶点坐标个数,如果是四个,精度刚好合适,终止循环
break
elif len(approx) < 4: # 如果小于四个,提高精度,进行迭代
a -= 0.05
else: # 如果大于四个,减小精度,进行迭代
a += 0.05
if a <= 0: # 如果a迭代为0或负值,终止迭代
break
elif a >= 0.3: # 如果a迭代为0或负值,终止迭代
break
cv2.drawContours(img_color_copy5, [approx], -1, (0, 0, 255),
4) # 将近似图像画出来 approx[0]左下,approx[1]右下,approx[2]右上,approx[3]左上(并不一定都会按照如此的顺序)
# 这里存在一个bug。这个bug应该是cv2.approxPolyDP()函数自带的,四个顶点存在一定顺序,但是并不一定是从右上角开始的,这里需要特别注意,容易出bug!!
# 且这个顺序在网上说是逆时针的,但实际应用的时候可以发现是顺时针的
# 为了防止近似轮廓不是从右上角开始的bug,我们需要进行一个判断:
if (approx[3][0][1] < approx[1][0][1]) & (
approx[3][0][0] < approx[1][0][0]): # 如果approx[3][0]为左上、approx[1][0]为右下
center = approx[3][0][0] + int((approx[1][0][0] - approx[3][0][0]) / 2), approx[3][0][1] + int(
(approx[1][0][1] - approx[3][0][1]) / 2) # 确定近似轮廓的中心
cv2.putText(img_color_copy5, str(n), center, cv2.FONT_HERSHEY_SIMPLEX, 5, (0, 0, 255), 2) # 标号
cv2.circle(img_color_copy5, center, 20, (0, 0, 255), -1) # 画中心
img_local = img_color_copy5[approx[3][0][1]:approx[1][0][1], approx[3][0][0]: approx[1][0][0]] # 获取单个光伏板图像
cv2.imwrite(dir_name + "/" + str(n) + ".jpg", img_local)
src = np.float32([approx[0][0], approx[1][0], approx[2][0], approx[3][0]]) # 确定原图上的四个点,这里用近似轮廓的四个点
dst = np.float32([[660, 0], [660, 1110], [0, 1110], [0, 0]]) # 确定仿射变换后对应的四个点
M = cv2.getPerspectiveTransform(src, dst) # 确定放射变换矩阵
img_p = cv2.warpPerspective(img_color_copy5, M, (660, 1110)) # 进行透视变换
cv2.imwrite(dir_name + "/" + str(n) + "-Perspective.jpg", img_p)
elif (approx[3][0][1] > approx[1][0][1]) & (
approx[3][0][0] > approx[1][0][0]): # 如果approx[3][0]为右下、approx[1][0]为左上
center = approx[1][0][0] + int((approx[3][0][0] - approx[1][0][0]) / 2), approx[1][0][1] + int(
(approx[3][0][1] - approx[1][0][1]) / 2) # 确定近似轮廓的中心
cv2.putText(img_color_copy5, str(n), center, cv2.FONT_HERSHEY_SIMPLEX, 5, (0, 0, 255), 2) # 标号
cv2.circle(img_color_copy5, center, 20, (0, 0, 255), -1) # 画中心
img_local = img_color_copy5[approx[1][0][1]:approx[3][0][1], approx[1][0][0]: approx[3][0][0]] # 获取单个光伏板图像
cv2.imwrite(dir_name + "/" + str(n) + ".jpg", img_local)
src = np.float32([approx[0][0], approx[1][0], approx[2][0], approx[3][0]]) # 确定原图上的四个点,这里用近似轮廓的四个点
dst = np.float32([[0, 1110], [0, 0], [660, 0], [660, 1110]]) # 确定仿射变换后对应的四个点
M = cv2.getPerspectiveTransform(src, dst) # 确定放射变换矩阵
img_p = cv2.warpPerspective(img_color_copy5, M, (660, 1110)) # 进行透视变换
cv2.imwrite(dir_name + "/" + str(n) + "-Perspective.jpg", img_p)
elif (approx[0][0][1] > approx[2][0][1]) & (
approx[0][0][0] > approx[2][0][0]): # 如果approx[0][0]为右下、approx[2][0]为左上
center = approx[2][0][0] + int((approx[0][0][0] - approx[2][0][0]) / 2), approx[2][0][1] + int(
(approx[0][0][1] - approx[2][0][1]) / 2) # 确定近似轮廓的中心
cv2.putText(img_color_copy5, str(n), center, cv2.FONT_HERSHEY_SIMPLEX, 5, (0, 0, 255), 2) # 标号
cv2.circle(img_color_copy5, center, 20, (0, 0, 255), -1) # 画中心
img_local = img_color_copy5[approx[2][0][1]:approx[0][0][1], approx[2][0][0]: approx[0][0][0]] # 获取单个光伏板图像
cv2.imwrite(dir_name + "/" + str(n) + ".jpg", img_local)
src = np.float32([approx[0][0], approx[1][0], approx[2][0], approx[3][0]]) # 确定原图上的四个点,这里用近似轮廓的四个点
dst = np.float32([[660, 1110], [0, 1110], [0, 0], [660, 0]]) # 确定仿射变换后对应的四个点
M = cv2.getPerspectiveTransform(src, dst) # 确定放射变换矩阵
img_p = cv2.warpPerspective(img_color_copy5, M, (660, 1110)) # 进行透视变换
cv2.imwrite(dir_name + "/" + str(n) + "-Perspective.jpg", img_p)
elif (approx[2][0][1] > approx[0][0][1]) & (
approx[2][0][0] > approx[0][0][0]): # 如果approx[2][0]为右下、approx[0][0]为左上
center = approx[0][0][0] + int((approx[2][0][0] - approx[0][0][0]) / 2), approx[0][0][1] + int(
(approx[2][0][1] - approx[0][0][1]) / 2) # 确定近似轮廓的中心
cv2.putText(img_color_copy5, str(n), center, cv2.FONT_HERSHEY_SIMPLEX, 5, (0, 0, 255), 2) # 标号
cv2.circle(img_color_copy5, center, 20, (0, 0, 255), -1) # 画中心
img_local = img_color_copy5[approx[0][0][1]:approx[2][0][1], approx[0][0][0]: approx[2][0][0]] # 获取单个光伏板图像
cv2.imwrite(dir_name + "/" + str(n) + ".jpg", img_local)
src = np.float32([approx[0][0], approx[1][0], approx[2][0], approx[3][0]]) # 确定原图上的四个点,这里用近似轮廓的四个点
dst = np.float32([[0, 0], [660, 0], [660, 1110], [0, 1110]]) # 确定仿射变换后对应的四个点
M = cv2.getPerspectiveTransform(src, dst) # 确定放射变换矩阵
img_p = cv2.warpPerspective(img_color_copy5, M, (660, 1110)) # 进行透视变换
cv2.imwrite(dir_name + "/" + str(n) + "-Perspective.jpg", img_p)
print(n)
n += 1
cv2.imwrite(dir_name + "/" + "img_color5_approx.jpg", img_color_copy5)
记录123123
最新推荐文章于 2024-07-30 10:53:26 发布