二值图像中旋转正方形的质心、边长及旋转角求解咨询
解决方案
1. 质心计算(原代码逻辑正确)
黑色像素的坐标均值就是正方形的质心,注意图像采用y轴优先的行主序,所以black_pixels的第一列是y坐标,第二列是x坐标:
black_pixels = np.argwhere(img == 0) y_centroid, x_centroid = np.mean(black_pixels, axis=0)
2. 获取正方形顶点
正方形的顶点是到质心距离最远的4个像素点,利用这一特性筛选顶点:
# 计算每个像素到质心的相对坐标 centered = black_pixels - np.array([y_centroid, x_centroid]) # 计算距离平方(避免开方,提升计算效率) dist_sq = np.sum(centered ** 2, axis=1) # 获取距离最远的4个点的索引 top4_idx = np.argpartition(dist_sq, -4)[-4:] vertices = black_pixels[top4_idx]
3. 计算边长l
旋转后的正方形因抗锯齿导致黑色像素数不等于l²,通过顶点间距离计算边长更准确:
# 生成所有顶点两两组合的索引(用numpy实现,无需额外库) idxs = np.triu_indices(4, k=1) pairs = vertices[idxs[0]], vertices[idxs[1]] # 计算每对顶点的距离 distances = np.sqrt(np.sum((pairs[0] - pairs[1]) ** 2, axis=1)) # 筛选出边长(对角线长度约为边长的√2倍,以此区分) sorted_dist = np.sort(distances) side_mask = sorted_dist < sorted_dist[-1] * 0.8 # 0.8用于区分边长和对角线 side_length = np.mean(sorted_dist[side_mask])
4. 计算旋转角alpha
正方形顶点位于对角线方向,将对角线角度减去45°即可得到边的旋转角,再处理等价角度:
# 取任意顶点到质心的向量 vec = vertices[0] - np.array([y_centroid, x_centroid]) # 计算向量与x轴的逆时针夹角(适配图像y轴向下的特性) angle_rad = np.arctan2(vec[0], vec[1]) angle_deg = np.degrees(angle_rad) # 对角线角度比边的旋转角大45°,因此减去45° alpha = angle_deg - 45 # 调整角度到0°~90°范围,处理等价角度(如0°与90°等价) alpha = alpha % 90
完整修正代码
import numpy as np def find_rect(img): # 找到所有黑色像素 black_pixels = np.argwhere(img == 0) if len(black_pixels) == 0: return 0, 0, 0, 0 # 计算质心 y_centroid, x_centroid = np.mean(black_pixels, axis=0) # 获取正方形顶点 centered = black_pixels - np.array([y_centroid, x_centroid]) dist_sq = np.sum(centered ** 2, axis=1) top4_idx = np.argpartition(dist_sq, -4)[-4:] vertices = black_pixels[top4_idx] # 计算边长 idxs = np.triu_indices(4, k=1) pairs = vertices[idxs[0]], vertices[idxs[1]] distances = np.sqrt(np.sum((pairs[0] - pairs[1]) ** 2, axis=1)) sorted_dist = np.sort(distances) side_mask = sorted_dist < sorted_dist[-1] * 0.8 side_length = np.mean(sorted_dist[side_mask]) # 计算旋转角 vec = vertices[0] - np.array([y_centroid, x_centroid]) angle_rad = np.arctan2(vec[0], vec[1]) angle_deg = np.degrees(angle_rad) alpha = angle_deg - 45 alpha = alpha % 90 return x_centroid, y_centroid, side_length, alpha # 保留原生成旋转正方形的代码 from scipy.ndimage import rotate def generate_rot_square(w, h, x, y, l, alpha): rect = np.ones((l, l)) rect = rotate(rect, alpha) r_h, r_w = rect.shape r_h_1 = r_h // 2 r_h_2 = r_h - r_h_1 r_w_1 = r_w // 2 r_w_2 = r_w - r_w_1 result = np.zeros((h, w), dtype=bool) result[y - r_h_1:y + r_h_2, x - r_w_1:x + r_w_2] = rect > 0.9 return 1 - result
关键说明
- 质心计算:原代码逻辑正确,直接取黑色像素坐标均值即可。
- 边长计算:旋转后的正方形因抗锯齿导致黑色像素数偏离
l²,通过顶点间距离计算更精准。 - 旋转角计算:利用正方形顶点在对角线上的特性,将对角线角度转换为边的旋转角,再通过取模90°处理等价角度。
内容的提问来源于stack exchange,提问作者Felix
相关产品推荐
相关产品推荐

