使用OpenCV对点集从左上到右下排序

本文实现如何使用OpenCV对点集从左上到右下排序。本文使用的案例图片如下:
在这里插入图片描述
需要实现的效果如下:
请添加图片描述

1.分阶段实现

让我们看看考虑4行的工作流。我考虑的是沿着y轴将图像分成4段,形成4行。对于图像的每一段,找出每一个以该段为中心的形状。最后,按每个线段的x坐标排列形状。

1.1导入必要的库:

import cv2
import numpy as np

1.2.定义一个辅助函数

它将接收一个图像输入,并将处理后的图像返回给某个对象,以便python稍后检索它们的轮廓:

def process_img(img):
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img_canny = cv2.Canny(img_gray, 100, 100)
    kernel = np.ones((2, 3))
    img_dilate = cv2.dilate(img_canny, kernel, iterations=1)
    img_erode = cv2.erode(img_dilate, kernel, iterations=1)
    return img_erode

1.3.定义一个返回轮廓中心的函数:

def get_centeroid(cnt):
    length = len(cnt)
    sum_x = np.sum(cnt[..., 0])
    sum_y = np.sum(cnt[..., 1])
    return int(sum_x / length), int(sum_y / length)

1.4.定义获取所有中心点的函数

它接收处理后的图像,并返回图像中找到的形状的中心点:

def get_centers(img):
    contours, hierarchies = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    for cnt in contours:
        if cv2.contourArea(cnt) > 100:
            yield get_centeroid(cnt)

1.5.定义一个获取每行中心点的函数

该函数接受图像img、中心点坐标centers、图像的段数row_amt和图像高度row_h作为输入。它将返回row_amt数组(根据它们的x坐标排序),每个数组都包含位于图像对应行中心的每个点:

def get_rows(img, centers, row_amt, row_h):
    centers = np.array(centers)
    d = row_h / row_amt
    for i in range(row_amt):
        f = centers[:, 1] - d * i
        a = centers[(f < d) & (f > 0)]
        yield a[a.argsort(0)[:, 0]]

1.6.实现中心点提取

读取图像,使用定义的处理函数得到其处理后的形状,使用定义的中心函数得到图像中每个形状的中心:

img = cv2.imread("shapes.png")
img_processed = process_img(img)
centers = list(get_centers(img_processed))

1.7.定义相关变量

获取图像的高度,用于定义的get_rows函数,并定义一个计数变量count:

h, w, c = img.shape
count = 0

1.8.可视化结果

循环遍历被分为4行的形状的中心,画一条线连接这些行,以便显示:

for row in get_rows(img, centers, 4, h):
    cv2.polylines(img, [row], False, (255, 0, 255), 2)
    for x, y in row:

1.9.在每个中心点上计标号

		count += 1
        cv2.circle(img, (x, y), 10, (0, 0, 255), -1)  
        cv2.putText(img, str(count), (x - 10, y + 5), 1, cv2.FONT_HERSHEY_PLAIN, (0, 255, 255), 2)

1.10.显示

cv2.imshow("Ordered", img)
cv2.waitKey(0)

2.完整代码

import cv2
import numpy as np

def process_img(img):
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img_canny = cv2.Canny(img_gray, 100, 100)
    kernel = np.ones((2, 3))
    img_dilate = cv2.dilate(img_canny, kernel, iterations=1)
    img_erode = cv2.erode(img_dilate, kernel, iterations=1)
    return img_erode
    
def get_centeroid(cnt):
    length = len(cnt)
    sum_x = np.sum(cnt[..., 0])
    sum_y = np.sum(cnt[..., 1])
    return int(sum_x / length), int(sum_y / length)

def get_centers(img):
    contours, hierarchies = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    for cnt in contours:
        if cv2.contourArea(cnt) > 100:
            yield get_centeroid(cnt)

def get_rows(img, centers, row_amt, row_h):
    centers = np.array(centers)
    d = row_h / row_amt
    for i in range(row_amt):
        f = centers[:, 1] - d * i
        a = centers[(f < d) & (f > 0)]
        yield a[a.argsort(0)[:, 0]]

img = cv2.imread("shapes.png")
img_processed = process_img(img)
centers = list(get_centers(img_processed))

h, w, c = img.shape
count = 0

for row in get_rows(img, centers, 4, h):
    cv2.polylines(img, [row], False, (255, 0, 255), 2)
    for x, y in row:
        count += 1
        cv2.circle(img, (x, y), 10, (0, 0, 255), -1)  
        cv2.putText(img, str(count), (x - 10, y + 5), 1, cv2.FONT_HERSHEY_PLAIN, (0, 255, 255), 2)

cv2.imshow("Ordered", img)
cv2.waitKey(0)

3.结果展示

下面是当你指定4行时的编号图像:
请添加图片描述
下面是指定6行时的编号图像:
请添加图片描述

参考目录

https://stackoverflow.com/questions/66946804/python-sorting-items-from-top-left-to-bottom-right-with-opencv

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值