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

news2024/9/22 1:23:39

本文实现如何使用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/188633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

虚拟主机怎么用?香港虚拟主机搭建网站教程

在了解使用方法之前要先明白什么是虚拟主机、它的用处以及服务器、VPS和虚拟主机之间有什么区别。香港虚拟主机也称为网站空间&#xff0c;顾名思义就是存放网站文件的空间。主要用于搭建网站、提供程序运行。下面就介绍一下香港虚拟主机搭建网站的使用方法以及教程。 一、香港…

职场新人应该如何培养项目管理的能力?

李强在一家企业工作&#xff0c;前阵子升任项目经理。但他这两天却一副愁眉不展的样子&#xff0c;像霜打的茄子。原来是因为他缺乏管理经验&#xff0c;设定的工作任务不合理&#xff0c;项目成员职责不清&#xff0c;导致项目混乱&#xff0c;项目进度不清晰。 项目管理涉及…

Redis搭建基于docker跨服务器的一主两从三哨兵集群模式

文章目录1 整体拓扑图2 redis与哨兵配置文件2.1 主节点配置文件2.1.1 主节点redis.conf配置文件2.1.2 主节点哨兵配置文件2.2 从节点配置文件2.1.1 从节点redis.conf配置文件2.1.2 从节点哨兵配置文件3 docke-compose编排文件4 启动并测试查看哨兵日志查看集群状态测试集群是否…

在 Visual Studio 中更好地进行搜索

当在 IDE 中查找特定的代码文件、类、方法或者功能、选项&#xff0c;找到它们并不总是那么容易。有多种搜索方式&#xff0c;到底该选择哪一种才最便捷呢&#xff1f;新的“一站式”搜索&#xff08;All-In-One Search&#xff09;将代码和功能搜索合并到同一个 UI 中&#xf…

从GPT到chatGPT(三):GPT3(一)

#GPT3 文章目录前言正文摘要介绍方法模型结构训练数据集训练过程评估小结前言 OpenAI在放出GPT2后&#xff0c;并没有引起业界太大的影响和关注&#xff0c;究其原因&#xff0c;并不是zero-shot这种想法不够吸引人&#xff0c;而是GPT2表现出来的效果依然差强人意&#xff0c…

Unity数据持久化-PlayerPrefs

1. PlayerPrefs 是什么&#xff1f; 是Unity提供的可以用于存储读取玩家数据的公共类 1.1. 存储相关 PlayerPrefs的数据存储类似于键值对存储 一个键对应一个值 提供了存储3种数据的方法int float string 键:string类型 值: int float string对应3种API PlayerPrefs.SetInt(…

如何将宿主机工作文件夹映射到vmware虚拟机内

将宿主机工作文件夹映射到vmware虚拟机内vmware启用共享文件夹在虚拟机中使用vmtools进行挂载虚拟机为linux系统&#xff0c;操作中使用的是凝思系统 vmware启用共享文件夹 在vmware中将需要共享的工作文件夹添加到共享列表中&#xff0c;如图 在虚拟机中使用vmtools进行挂…

Tomcat部署项目及Tomcat间会话同步

目录一、Tomcat中部署项目的相关配置1.相关配置2.测试二、Tomcat间的会话同步1.配置Tomcat2.修改web工程的WEB-INF下的web.xml3.配置Nginx4.测试一、Tomcat中部署项目的相关配置 1.相关配置 在Tomcat中进入conf/tomcat-users.xml文件&#xff0c;将以下代码放到最后 <rol…

本地Exchange备份方案

Exchange Server的Windows服务器备份只能执行基础还原&#xff0c;并且不支持对邮箱项执行粒度还原。在需要恢复单个已删除的电子邮件或文件夹的情况下&#xff0c;本机解决方案提供了一个耗时且低效的过程。Exchange ServerRecoveryManager Plus帮助您克服这些限制。使用Recov…

国内有哪些移动开发平台?各有什么特点

开年找解决方案的时候接触了一批移动开发平台&#xff0c;猛然发现近几年移动开发平台如雨后春笋般出现&#xff0c;于是乎就想针对市场上越来越多的移动开发平台做一次盘点对比&#xff0c;看看他们的基本情况和自身特点优势&#xff0c;也希望能够对有需要的开发者有一定的参…

Docker - 4. 容器常用命令 docker run、exit、ps、rm、start、stop、kill

目录 1. 新建容器并启动 2. 从容器中退回主机 3. 列出所有运行的容器 4. 退出容器 5. 删除容器 6. 启动和停止容器 7. 易混淆地方 1. 新建容器并启动 语法&#xff1a;docker run [可选参数] 镜像名 参数&#xff1a; 参数含义--name "Name" 容器名字&a…

java泛型1

泛型&#xff08;为了集合&#xff09; Java 5增加泛型支持在很大程度上都是为了让集合能记住其元素的数据类型。在没有泛型之前&#xff0c;一旦把一个对象“丢进”Java集合中&#xff0c;集合就会忘记对象的类型&#xff0c;把所有的对象当成Object类型处理。当程序从集合中取…

基于深度学习框架设计的货运管家(功能总结)

项目背景&#xff1a; 在快递行业发达的今天&#xff0c;有数不胜数的货运公司、快递公司&#xff0c;这些公司都有自己的运输车辆&#xff0c;请师傅开车送货。 比如&#xff1a;快递公司、烟草运输公司、货物运输公司等等。 为了能方便管理货车&#xff0c;了解车辆行驶路线…

49.Isaac教程--Cartographer

Cartographer ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录Cartographer数据要求配置启动 Cartographer 示例应用程序监控和可视化输出Cartographer 是 Google 的一个&#xff08;同步定位和映射&#xff09;SLAM 系统&#xff0c;能够…

2023最新前端面试题5(持续更新)

Vue 74、vue 生命周期 74.1、什么是 Vue 生命周期? Vue 实例从创建到销毁的过程&#xff0c;就是生命周期。也就是从开始创建、初始化数据编译模板、挂载 Dom一渲染、更新一渲染、卸载等一系列过程&#xff0c;我们称这是 Vue的生命周期 74.2、Vue 生命周期的作用是什么?…

函数递归+青蛙跳台阶——“C”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容终于要回到我们的C语言了&#xff0c;在之前&#xff0c;我写函数这篇博客的时候就讲过&#xff0c;会把函数递归的内容单独拿出来&#xff0c;然后呢当时是说下一篇博客就会更函数递归和青蛙跳台阶&#xff0c;由于一系列原…

拼多多控价,低价投诉,不被支持怎么办

治理电商平台上的低价乱价链接&#xff0c;首选方法是沟通调整&#xff0c;成本低、见效快。针对沟通调整不成功的&#xff0c;再进行平台投诉&#xff0c;通过电商平台的力量对其进行约束。 但是&#xff0c;平台投诉一定要注意一点&#xff1a;不要以低价为理由&#xff01;…

原命题和逆否命题

看Boyd的凸优化看到这样一个证明&#xff1a; 从左到右的证明是 使用了一个逆否命题的方法进行证明&#xff0c;有点忘记了原命题和逆否命题之间的相互转换&#xff0c;记录一下。 简单形式命题 简单形式命题没有全称量词∀\forall∀和存在两次∃\exists∃&#xff0c;也没有…

字符流、字节流、缓冲流、序列化流

1.文件拷贝的基本代码 2.一次读取多个字节 3.异常处理 但是上述的释放过程太繁琐&#xff0c;于是便用AutoCloseable接口简化释放过程 JDK7: JDK9: 4.各种字词计算机存储规则 所以底层二进制文件就是根据正负来区别英文和中文的。 5.乱码 6.字符流 7.字符输入流和输出流底层原理…

ASEMI桥式整流电路KBP206特性参数的计算

编辑-Z 什么是桥式整流电路&#xff1f; 桥式整流电路由四个二极管以闭环“桥式”配置连接&#xff0c;以产生所需的输出。这种桥式电路的主要优点是不需要特殊的中央抽头变压器&#xff0c;从而减小了尺寸和成本。单个次级绕组连接到二极管桥网络的一侧&#xff0c;负载连接到…