请直接从正文看
我是看了一位老哥的分享才对参数了解的:
全(中文)网都错的相机畸变参数到底怎么写?——相机畸变校正公式的正确写法-CSDN博客
然后我总结的就是我的摄像头的畸变系数是-10%
是亚博的一款摄像头,但是我的参数设定看来,要-0.35才可以
然后调整了畸变的结果是和墙边的桌子边线平行
然后我还使用了图像压缩,我一开始就只用的矫正畸变但是看起来效果不怎么样
但是当我尝试图像在y轴压缩时,直接就看起来正常了
正文:
最近在做图像处理相关的项目时,遇到了一个棘手的问题:摄像头拍摄的图像存在畸变,导致后续的图像分析和处理效果不佳。经过一番研究和实践,我终于找到了解决问题的方法,并且还实现了形状检测功能。今天就来和大家分享一下我的经验。
一、相机畸变校正的探索
在开始之前,我先简单介绍一下相机畸变。相机畸变是指由于镜头的光学特性,导致拍摄的图像与实际物体形状不一致的现象。常见的畸变有桶形畸变和枕形畸变,它们会让图像的边缘部分看起来变形。
一开始,我参考了网上的资料,发现很多人都在使用畸变系数来校正图像。但是,我发现全网对于畸变系数的设定似乎都存在一些误解。很多人直接使用 -10%(即 -0.1)作为畸变系数,但在我实际测试中,这个值并不适用。
我使用的是亚博的一款摄像头,经过多次试验,我发现只有将畸变系数设置为 -0.35 时,校正后的图像效果才最接近真实场景。为了验证这一点,我将校正后的图像与墙边的桌子边线进行对比,发现它们已经能够很好地平行对齐了。
二、畸变校正代码实现
为了实现畸变校正,我编写了以下代码:
import cv2
import numpy as np
def undistort_image(image, distortion_coefficient=-0.35):
"""
对图像进行畸变校正
参数:
image: 输入图像
distortion_coefficient: 畸变系数,默认为 -0.35
返回:
校正后的图像
"""
# 获取图像尺寸
h, w = image.shape[:2]
# 构造相机内参矩阵
camera_matrix = np.array([[w, 0, w/2],
[0, h, h/2],
[0, 0, 1]], dtype=np.float32)
# 构造畸变系数数组
dist_coeffs = np.array([distortion_coefficient, 0, 0, 0], dtype=np.float32)
# 进行畸变校正
undistorted_image = cv2.undistort(image, camera_matrix, dist_coeffs)
return undistorted_image
这段代码的核心是 cv2.undistort
函数,它可以根据相机内参矩阵和畸变系数对图像进行校正。通过调整畸变系数,我们可以得到最佳的校正效果。
三、图像压缩与形状检测
在畸变校正的基础上,我还尝试了图像压缩和形状检测。我发现仅仅进行畸变校正的效果并不理想,但当我对图像进行 y 轴压缩后,图像看起来更加正常了。这让我意识到,有时候我们需要结合多种方法来优化图像处理效果。
为了实现形状检测,我编写了以下代码:
def ShapeDetection(imgContour, cnt):
# 计算轮廓的周长
perimeter = cv2.arcLength(cnt, True)
# 多边形近似
approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True)
corners = len(approx)
# 计算轮廓的面积
area = cv2.contourArea(cnt)
if area < 500:
return None
x, y, w, h = cv2.boundingRect(approx)
# 三角形检测
if corners == 3:
# 计算三角形的边长
pts = approx.reshape(3, 2)
d1 = np.linalg.norm(pts[0] - pts[1])
d2 = np.linalg.norm(pts[1] - pts[2])
d3 = np.linalg.norm(pts[2] - pts[0])
# 计算三角形的角度
angles = []
for i in range(3):
p1 = pts[i]
p2 = pts[(i + 1) % 3]
p3 = pts[(i + 2) % 3]
v1 = p2 - p1
v2 = p3 - p1
cos_theta = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
angle = np.arccos(np.clip(cos_theta, -1, 1)) * 180 / np.pi
angles.append(angle)
# 判断是否为有效三角形
if all(angle < 170 for angle in angles) and all(d > 5 for d in [d1, d2, d3]):
cv2.drawContours(imgContour, [approx], -1, (255, 0, 0), 3)
cv2.putText(imgContour, "Triangle", (x + w // 2 - 40, y + h // 2 + 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
return "Triangle"
# 矩形检测
elif corners == 4:
pts = approx.reshape(4, 2)
angles = []
for i in range(4):
p1 = pts[i]
p2 = pts[(i + 1) % 4]
p3 = pts[(i + 2) % 4]
v1 = p2 - p1
v2 = p3 - p2
cos_theta = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
angle = np.arccos(np.clip(cos_theta, -1, 1)) * 180 / np.pi
angles.append(angle)
# 判断是否为矩形
if all(abs(90 - a) < 10 for a in angles):
rotated_rect = cv2.minAreaRect(approx)
width, height = rotated_rect[1]
aspect_ratio = width / float(height)
if 0.85 < aspect_ratio < 1.15:
cv2.drawContours(imgContour, [approx], -1, (255, 0, 0), 3)
cv2.putText(imgContour, "Square", (x + w // 2 - 40, y + h // 2 + 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
return "Square"
else:
cv2.drawContours(imgContour, [approx], -1, (255, 0, 0), 3)
cv2.putText(imgContour, "Rectangle", (x + w // 2 - 40, y + h // 2 + 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
return "Rectangle"
# 圆形检测
elif corners >= 8:
(cx, cy), radius = cv2.minEnclosingCircle(cnt)
circularity = 4 * np.pi * area / (perimeter ** 2)
if 0.7 < circularity < 1.2 and radius > 10:
cv2.drawContours(imgContour, [cnt], -1, (255, 0, 0), 3)
cv2.putText(imgContour, "Circle", (int(cx) - 40, int(cy) + 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
return "Circle"
return None
这段代码通过计算轮廓的周长、多边形近似、角度等信息,实现了对三角形、矩形、正方形和圆形的检测。在检测到形状后,会在图像上绘制轮廓并标注形状类型。
四、完整流程与效果展示
最后,我将畸变校正、图像压缩和形状检测结合起来,实现了完整的图像处理流程。以下是完整的代码:
import cv2
import numpy as np
import time
from collections import defaultdict
# 畸变校正函数
def undistort_image(image, distortion_coefficient=-0.35):
"""
对图像进行畸变校正
参数:
image: 输入图像
distortion_coefficient: 畸变系数,默认为 -0.35
返回:
校正后的图像
"""
# 获取图像尺寸
h, w = image.shape[:2]
# 构造相机内参矩阵
camera_matrix = np.array([[w, 0, w/2],
[0, h, h/2],
[0, 0, 1]], dtype=np.float32)
# 构造畸变系数数组
dist_coeffs = np.array([distortion_coefficient, 0, 0, 0], dtype=np.float32)
# 进行畸变校正
undistorted_image = cv2.undistort(image, camera_matrix, dist_coeffs)
return undistorted_image
# 形状检测函数
def ShapeDetection(imgContour, cnt):
# 计算轮廓的周长
perimeter = cv2.arcLength(cnt, True)
# 多边形近似
approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True)
corners = len(approx)
# 计算轮廓的面积
area = cv2.contourArea(cnt)
if area < 500:
return None
x, y, w, h = cv2.boundingRect(approx)
# 三角形检测
if corners == 3:
# 计算三角形的边长
pts = approx.reshape(3, 2)
d1 = np.linalg.norm(pts[0] - pts[1])
d2 = np.linalg.norm(pts[1] - pts[2])
d3 = np.linalg.norm(pts[2] - pts[0])
# 计算三角形的角度
angles = []
for i in range(3):
p1 = pts[i]
p2 = pts[(i + 1) % 3]
p3 = pts[(i + 2) % 3]
v1 = p2 - p1
v2 = p3 - p1
cos_theta = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
angle = np.arccos(np.clip(cos_theta, -1, 1)) * 180 / np.pi
angles.append(angle)
# 判断是否为有效三角形
if all(angle < 170 for angle in angles) and all(d > 5 for d in [d1, d2, d3]):
cv2.drawContours(imgContour, [approx], -1, (255, 0, 0), 3)
cv2.putText(imgContour, "Triangle", (x + w // 2 - 40, y + h // 2 + 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
return "Triangle"
# 矩形检测
elif corners == 4:
pts = approx.reshape(4, 2)
angles = []
for i in range(4):
p1 = pts[i]
p2 = pts[(i + 1) % 4]
p3 = pts[(i + 2) % 4]
v1 = p2 - p1
v2 = p3 - p2
cos_theta = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
angle = np.arccos(np.clip(cos_theta, -1, 1)) * 180 / np.pi
angles.append(angle)
# 判断是否为矩形
if all(abs(90 - a) < 10 for a in angles):
rotated_rect = cv2.minAreaRect(approx)
width, height = rotated_rect[1]
aspect_ratio = width / float(height)
if 0.85 < aspect_ratio < 1.15:
cv2.drawContours(imgContour, [approx], -1, (255, 0, 0), 3)
cv2.putText(imgContour, "Square", (x + w // 2 - 40, y + h // 2 + 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
return "Square"
else:
cv2.drawContours(imgContour, [approx], -1, (255, 0, 0), 3)
cv2.putText(imgContour, "Rectangle", (x + w // 2 - 40, y + h // 2 + 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
return "Rectangle"
# 圆形检测
elif corners >= 8:
(cx, cy), radius = cv2.minEnclosingCircle(cnt)
circularity = 4 * np.pi * area / (perimeter ** 2)
if 0.7 < circularity < 1.2 and radius > 10:
cv2.drawContours(imgContour, [cnt], -1, (255, 0, 0), 3)
cv2.putText(imgContour, "Circle", (int(cx) - 40, int(cy) + 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
return "Circle"
return None
# 摄像头捕获
cap = cv2.VideoCapture(1)
# 初始化时间变量
start_time = time.time()
# 裁剪区域 (根据实际情况调整)
x_start = 210 # 裁剪区域的起始x坐标
y_start = 60 # 裁剪区域的起始y坐标
x_end = 390 # 裁剪区域的结束x坐标
y_end = 340 # 裁剪区域的结束x坐标
while True:
ret, frame = cap.read()
if not ret:
break
# 对图像进行畸变校正
frame = undistort_image(frame)
# 压缩图像尺寸,最后试出来的
frame = cv2.resize(frame, (640, 400))
# 裁剪图像
frame = frame[y_start:y_end, x_start:x_end]
# 后续处理使用校正后的图像
imgContour = frame.copy()
# 转换为灰度图像
imgGray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 高斯模糊
imgBlur = cv2.GaussianBlur(imgGray, (7, 7), 1)
# 二值化处理
_, imgThresh = cv2.threshold(imgBlur, 95, 255, cv2.THRESH_BINARY_INV)
# 边缘检测
edges = cv2.Canny(imgBlur, 30, 150)
# 边缘和二值化图像合并
imgCanny = cv2.bitwise_or(edges, imgThresh)
# 闭运算
kernel = np.ones((3, 3), np.uint8)
imgCanny = cv2.morphologyEx(imgCanny, cv2.MORPH_CLOSE, kernel)
# 轮廓检测
contours, _ = cv2.findContours(imgCanny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 初始化形状计数器
shape_counts = defaultdict(int)
for cnt in contours:
shape_type = ShapeDetection(imgContour, cnt)
if shape_type:
shape_counts[shape_type] += 1
# 打印形状计数
current_time = time.time()
if current_time - start_time >= 1.0:
# 记录每秒的形状计数
if shape_counts:
# 找到每种形状的众数数量
triangle_count = shape_counts.get("Triangle", 0)
rectangle_count = shape_counts.get("Rectangle", 0)
square_count = shape_counts.get("Square", 0)
circle_count = shape_counts.get("Circle", 0)
print(f"Triangles: {triangle_count}, Rectangles: {rectangle_count}, Squares: {square_count}, Circles: {circle_count}")
else:
print("No shapes detected")
start_time = current_time
cv2.imshow("Contours", imgContour)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
运行这段代码后,我们可以看到摄像头拍摄的图像经过畸变校正、压缩和形状检测后,能够清晰地识别出三角形、矩形、正方形和圆形,并在图像上标注出来。同时,程序还会实时统计每秒检测到的各种形状的数量。
五、总结
结合图像压缩和形状检测,可以进一步优化图像处理效果。
如果你也遇到了类似的问题,不妨尝试调整畸变系数,并结合其他图像处理方法来达到最佳效果。希望我的经验能对你有所帮助!