【图像配准】Canny边缘检测+模板配准红外可见光双路数据

2023-10-25 15:13:37 浏览数 (2)

研究目的

最近在做无人机遥感红外和可见光双路数据配准,由于红外相机视野范围较小,因此配准的目的主要是在可见光的视野范围内,裁剪出红外图像对应的部分,同时,保持可见光的高分辨率不变。

本文思路

本文尝试使用Canny边缘检测提取红外和可见光的边缘特征,然后使用模板匹配的方式去进行配准。由于红外图像和可见光图像的分辨率并不相同,因此需要对可见光不断进行下采样,以接近红外图像的分辨率。

总体看来,使用传统方法做跨模态配准效果有限,主要是由于红外图像特征较少,不过在光照充足和建筑特征明显的情况下,有一定效果,后续会采用基于深度学习的配准方法,相关图片由于项目原因不对外公布,这里对代码进行归档。

实验代码

代码语言:javascript复制
import numpy as np
import argparse
import cv2
import os

if __name__ == '__main__':
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--image", required=False, default=r"lr/Infrared.jpg", help="红外图像路径")
    ap.add_argument("-v", "--visualize", required=False, default=r"rgb/Zoom.jpg", help="可见光图像路径")
    ap.add_argument("-o", "--output", required=False, default=r"output", help="输出文件夹路径")
    args = vars(ap.parse_args())

    # 读取红外图像/灰度化/边缘检测
    template = cv2.imread(args["image"])
    template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
    template = cv2.Canny(template, 50, 200)
    (tH, tW) = template.shape[:2]

    # 读取可见光图像
    image = cv2.imread(args["visualize"])
    # image = cv2.resize(image, (tW, tH))
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    found = None

    for scale in np.linspace(0.2, 1.0, 20)[::-1]:
        # 多尺度缩小可见光图像
        resized = cv2.resize(gray, (int(gray.shape[1] * scale), int(gray.shape[0] * scale)))
        r = gray.shape[1] / float(resized.shape[1])

        # 若缩小的尺度小于红外图像尺寸,跳出循环
        if resized.shape[0] < tH or resized.shape[1] < tW:
            break

        # 对缩小之后的图像进行边缘检测
        edged = cv2.Canny(resized, 50, 200)
        '''
        cv2.matchTemplate  模板匹配
        :param 检测图像 模板 模板匹配方法
        :returns 相似度结果矩阵:(宽: image.shape[1]-template.shape[1] 1; 高:image.shape[0]-template.shape[0] 1)
        '''
        result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF)
        # print("edged_shape:{}".format(edged.shape))  # (3888, 5184)
        # print("template_shape:{}".format(template.shape))  # (512, 640)
        # print("result_shape:{}".format(result.shape))  # (3377, 4545)

        # 查找模板中最大相似度值和位置
        _, maxVal, _, maxLoc = cv2.minMaxLoc(result)

        # 可选:查看匹配图范围
        # clone = np.dstack([edged, edged, edged])
        # clone = edged
        # cv2.rectangle(clone, (maxLoc[0], maxLoc[1]), (maxLoc[0]   tW, maxLoc[1]   tH), (0, 0, 255), 2)
        # cv2.imwrite(os.path.join(args["output"], "Visualize", "visualize.jpg"), clone)

        # 若在裁剪区域找到相似度更高的匹配点,更新found
        if found is None or maxVal > found[0]:
            found = (maxVal, maxLoc, r)

    # 得到匹配度最高的矩阵框坐标
    _, maxLoc, r = found
    (startX, startY) = (int(maxLoc[0] * r), int(maxLoc[1] * r))
    (endX, endY) = (int((maxLoc[0]   tW) * r), int((maxLoc[1]   tH) * r))

    # cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2)
    crop_img = image[startY:endY, startX:endX]
    # cv2.imshow("Image", image)
    # cv2.imshow("Crop Image", crop_img)
    # cv2.waitKey(0)


    thermal_image = cv2.imread(args["image"], cv2.IMREAD_COLOR)
    # cropping out the matched part of the thermal image
    crop_img = cv2.resize(crop_img, (thermal_image.shape[1], thermal_image.shape[0]))

    # 创建输出文件夹存储裁剪后的可见光影像
    if not os.path.exists(os.path.join(args["output"], "process")):
        os.mkdir(os.path.join(args["output"], "process"))
    # 保存图片
    cv2.imwrite(os.path.join(args["output"], "process", os.path.basename(args["visualize"])), crop_img)

    # 创建对比图像
    final = np.concatenate((crop_img, thermal_image), axis=1)
    if not os.path.exists(os.path.join(args["output"], "results")):
        os.mkdir(os.path.join(args["output"], "results"))
    cv2.imwrite(os.path.join(args["output"], "results", os.path.basename(args["visualize"])), final)

0 人点赞