Python+Kivy+OpenCV使用ORB算法进行特征点检测和匹配

在本文中,我们将介绍如何使用Kivy和OpenCV库来构建一个简单的图片定位工具。这个工具可以帮助您在一张大图片中找到与模板图片匹配的位置,并将匹配结果以矩形框的形式显示出来。
首先,我们需要安装Kivy和OpenCV库。Kivy是一个开源的Python库,用于开发多点触摸应用程序。OpenCV是一个开源的计算机视觉库,提供了许多图像处理和计算机视觉方面的功能。
在安装好Kivy和OpenCV之后,我们可以开始编写代码。首先,我们需要导入一些必要的库,并设置Kivy的版本要求。

1.导入所需的库
import cv2
import kivy
import numpy as np

from kivy.app import App
from kivy.core.image import Texture
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.core.text import LabelBase

LabelBase.register(name='Roboto', fn_regular='./msyh.ttc')

kivy.require('2.0.0')  # 确保使用Kivy的适当版本

导入字体部分可以搜索Kivy导入中文字体学习如何操作,以免Kivy的中文乱码

2.创建主界面类

我们创建一个名为MainScreen的类,它继承自BoxLayout。在这个类中,我们将创建一些必要的控件,如按钮、标签和图像显示控件。

class MainScreen(BoxLayout):
    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)
        self.image_widget = None
        self.locate_label = None
        self.locate_button = None
        self.orientation = "vertical"
        self.padding = 10
        self.spacing = 10
        self.create_widgets()
        self.bind_events()
        self.image_path = "1.png"  # 替换为您的图片路径
        self.template_path = "456.png"  # 替换为您的模板图像路径
        self.output_path = "678.png"  # 替换为您想要保存的输出图像路径


    def create_widgets(self):
        # 创建图片定位工具包按钮和标签
        self.locate_button = Button(text="图片定位")
        self.locate_label = Label(text="")
        self.image_widget = Image()  # 用于显示图像的Image控件
        self.add_widget(self.locate_button)
        self.add_widget(self.locate_label)
        self.add_widget(self.image_widget)

    def bind_events(self):
        # 绑定图片定位按钮的点击事件
        self.locate_button.bind(on_press=self.locate_image)

    
class MyApp(App):
    def build(self):
        return MainScreen()


if __name__ == "__main__":
    MyApp().run()
3.实现图片定位功能

在MainScreen类中,我们定义了一个名为  _locate_image_async  的方法,该方法将在用户点击“图片定位”按钮时被调用。在这个方法中,我们将使用OpenCV的ORB特征算法来在大图片中找到与模板图片匹配的位置。

先在  MainScreen 类里面的init函数中初始化ORB算法

class MainScreen(BoxLayout):
    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)
        self.image_widget = None
        self.locate_label = None
        self.locate_button = None
        self.orientation = "vertical"
        self.padding = 10
        self.spacing = 10
        self.create_widgets()
        self.bind_events()
        self.image_path = "1.png"  # 替换为您的图片路径
        self.template_path = "456.png"  # 替换为您的模板图像路径
        self.output_path = "678.png"  # 替换为您想要保存的输出图像路径

        self.detector = cv2.ORB_create()  # 初始化ORB和FLANN
        self.flann_params = dict(algorithm=0, trees=5)  # cv2.FLANN_KDTREE
        self.flann = cv2.FlannBasedMatcher(self.flann_params, {})

然后开始我们的特征匹配 

    def locate_image(self, instance):
        # 使用线程或异步来避免阻塞UI
        from kivy.clock import Clock
        Clock.schedule_once(self._locate_image_async, 0)

    def _locate_image_async(self, dt):
        try:
            # 调用detect_with_orb方法
            result, annotated_template = self.detect_with_orb()

            if result:
                self.locate_label.text = "图片定位成功!"
                self.show_image(annotated_template)
            else:
                self.locate_label.text = "图片定位失败。"
        except Exception as e:
            self.locate_label.text = f"发生错误:{e}"
            import traceback
            traceback.print_exc()
            print(e)

    def detect_with_orb(self):
        try:
            image = cv2.imread(self.image_path)
            template = cv2.imread(self.template_path)
            if image is None or template is None:
                raise ValueError("无法读取图像文件")
            gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            gray_template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)

            # 首先尝试使用ORB算法
            kp1, des1 = self.detector.detectAndCompute(gray_image, None)
            kp2, des2 = self.detector.detectAndCompute(gray_template, None)
            matches = self.flann.knnMatch(des1.astype(np.float32), des2.astype(np.float32), k=2)
            good = []
            for m, n in matches:
                if m.distance < 0.99 * n.distance:
                    good.append(m)
            if len(good) < 6:
                raise ValueError("ORB匹配点数量不足")
            # 如果ORB成功,则使用它进行后续步骤
            src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
            dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
            H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
            self.img3 = self.draw_img(H, gray_image, template)
            self.show_image(self.img3)
            return True, self.img3
        except Exception as e:
            self.locate_label.text = f"发生错误:{e}"
            import traceback
            traceback.print_exc()
            print(e)

    def draw_img(self, H, gray_image, template):
        #这个方法是将获取到的点在模板上画框框
        # 获取模板图像的四个角点
        h, w = template.shape[:2]
        template_corners = np.float32([[0, 0], [0, h], [w, h], [w, 0]]).reshape(-1, 1, 2)
        image_corners = cv2.perspectiveTransform(template_corners, H)
        # 在模板图像上绘制匹配点和矩形框
        template = template.copy()
        w2, h2 = gray_image.shape[::-1]
        for corner in image_corners:
            template = cv2.rectangle(template,
                                 (int(corner[0][0]) - int(w2 / 2), int(corner[0][1]) - int(h2 / 2)),
                                 (int(corner[0][0]) + int(w2 / 2), int(corner[0][1]) + int(h2 / 2)),
                                 (0, 255, 0), 2)
        cv2.imwrite(self.output_path, template)
        return template

    def show_image(self, image):
        # 确保图像数据是numpy数组,并且格式为BGRA
        if image.shape[2] == 3:  # 如果是RGB格式,则转换为BGRA
            image = cv2.cvtColor(image, cv2.COLOR_RGB2BGRA)
        # 对图像进行上下翻转
        image = cv2.flip(image, 0)
        # 创建Texture或更新现有的Texture
        if self.image_widget.texture is None or self.image_widget.texture.size != (image.shape[1], image.shape[0]):
            image_texture = Texture.create(size=(image.shape[1], image.shape[0]), colorfmt='rgba')
            self.image_widget.texture = image_texture
        # 更新Texture的内容
        self.image_widget.texture.blit_buffer(image.tobytes(), colorfmt='rgba', bufferfmt='ubyte')
        # 强制Kivy更新图像显示
        self.image_widget.canvas.ask_update()

使用这段代码对获取到的特征码进行筛选,这个0.99是可变动的阀值,可根据结果进行调整,当特征点比较少的时候恰当进行调整

            for m, n in matches:
                if m.distance < 0.99 * n.distance:
                    good.append(m)
            if len(good) < 6:
                raise ValueError("ORB匹配点数量不足")

还有就是个人感觉ORB算法当获取到的特征点比较少的时候是很难精准的进行匹配的

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KNN匹配和FLANN匹配是两种不同的特征匹配方法,它们都可以用于ORB特征检测和暴力匹配。 在ORB特征检测中,我们首先需要提取图像中的ORB特征点,然后使用暴力匹配或者KNN匹配或者FLANN匹配匹配这些特征点。 BF暴力匹配是最简单的匹配方法,它会将每个特征点与所有特征点进行比较,找到最佳匹配。而KNN匹配和FLANN匹配会更加智能一些,它们会根据特征点之间的距离和相似性来匹配特征点,从而提高匹配的准确性和效率。 KNN匹配会选择每个特征点的k个最佳匹配,然后通过比较这些匹配的距离和相似性来选择最佳匹配。FLANN匹配则是使用快速最近邻搜索算法来查找最佳匹配,这个算法可以在大规模数据集上运行得非常快。 在Python使用OpenCV实现ORB特征检测和KNN匹配或FLANN匹配需要用到cv2模块中的ORB和FlannBasedMatcher类。具体的代码实现可以参考以下示例: ```python import cv2 # 读取图像 img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE) img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE) # 初始化ORB检测器 orb = cv2.ORB_create() # 提取图像中的ORB特征点和描述符 kp1, des1 = orb.detectAndCompute(img1, None) kp2, des2 = orb.detectAndCompute(img2, None) # 初始化KNN匹配器 matcher = cv2.DescriptorMatcher_create(cv2.DESCRIPTOR_MATCHER_BRUTEFORCE_HAMMING) # 使用KNN匹配进行匹配 matches = matcher.knnMatch(des1, des2, k=2) # 使用FLANN匹配进行匹配 flann = cv2.FlannBasedMatcher() matches = flann.knnMatch(des1, des2, k=2) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值