热红外相机图片与可见光图片配准教程

news2024/12/23 22:58:05

一、前言

图像配准是一种图像处理技术,用于将多个场景对齐到单个集成图像中。在这篇文章中,我将讨论如何在可见光及其相应的热图像上应用图像配准。在继续该过程之前,让我们看看什么是热图像及其属性。

二、热红外数据介绍

热图像本质上通常是灰度图像:黑色物体是冷的,白色物体是热的,灰色的深度表示两者之间的差异。 然而,一些热像仪会为图像添加颜色,以帮助用户识别不同温度下的物体。

图1 左图为可见光;有图为热红外图像

上面两个图像是可见的,它是对应的热图像,你可以看到热图像有点被裁剪掉了。 这是因为在热图像中并没有捕获整个场景,而是将额外的细节作为元数据存储在热图像中。

因此,为了执行配准,我们要做的是找出可见图像的哪一部分出现在热图像中,然后对图像的该部分应用配准。

图2 .与热图像匹配后裁剪的可见图像

为了执行上述操作,基本上包含两张图像,一张参考图像和另一张要匹配的图像。 因此,下面的算法会找出参考图像的哪一部分出现在第二张图像中,并为您提供匹配图像部分的位置。

现在我们知道热图像中存在可见图像的哪一部分,我们可以裁剪可见图像,然后对生成的图像进行配准。

三、配准过程

为了执行配准,我们要做的是找出将像素从可见图像映射到热图像的特征点,这在本文中进行了解释,一旦我们获得了一定数量的像素,我们就会停止并开始映射这些像素,从而完成配准过程完成了。

图3 热成像到可见光图像配准

一旦我们执行了配准,如果匹配正确,我们将获得具有配准图像的输出,如下图所示。

图4 最终输出结果

我对 400 张图像的数据集执行了此操作,获得的结果非常好。 错误数量很少,请参考下面的代码,看看一切是如何完成的。


from __future__ import print_function
import numpy as np
import argparse
import glob
import cv2
import os

MAX_FEATURES = 500
GOOD_MATCH_PERCENT = 0.15

#function to align the thermal and visible image, it returns the homography matrix 
def alignImages(im1, im2,filename):
 
  # Convert images to grayscale
  im1Gray = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY)
  im2Gray = cv2.cvtColor(im2, cv2.COLOR_BGR2GRAY)
   
  # Detect ORB features and compute descriptors.
  orb = cv2.ORB_create(MAX_FEATURES)
  keypoints1, descriptors1 = orb.detectAndCompute(im1Gray, None)
  keypoints2, descriptors2 = orb.detectAndCompute(im2Gray, None)
   
  # Match features.
  matcher = cv2.DescriptorMatcher_create(cv2.DESCRIPTOR_MATCHER_BRUTEFORCE_HAMMING)
  matches = matcher.match(descriptors1, descriptors2, None)
   
  # Sort matches by score
  matches.sort(key=lambda x: x.distance, reverse=False)
 
  # Remove not so good matches
  numGoodMatches = int(len(matches) * GOOD_MATCH_PERCENT)
  matches = matches[:numGoodMatches]
 
  # Draw top matches
  imMatches = cv2.drawMatches(im1, keypoints1, im2, keypoints2, matches, None)
  if os.path.exists(os.path.join(args["output"],"registration")):
    pass
  else:
   os.mkdir(os.path.join(args["output"],"registration"))
  cv2.imwrite(os.path.join(args["output"],"registration",filename), imMatches)
   
  # Extract location of good matches
  points1 = np.zeros((len(matches), 2), dtype=np.float32)
  points2 = np.zeros((len(matches), 2), dtype=np.float32)
 
  for i, match in enumerate(matches):
    points1[i, :] = keypoints1[match.queryIdx].pt
    points2[i, :] = keypoints2[match.trainIdx].pt
   
  # Find homography
  h, mask = cv2.findHomography(points1, points2, cv2.RANSAC)
 
  # Use homography
  height, width, channels = im2.shape
  im1Reg = cv2.warpPerspective(im1, h, (width, height))
   
  return im1Reg, h

# construct the argument parser and parse the arguments
# run the file with python registration.py --image filename
ap = argparse.ArgumentParser()
# ap.add_argument("-t", "--template", required=True, help="Path to template image")
ap.add_argument("-i", "--image", required=False,default=r"热红外图像的路径",
    help="Path to images where thermal template will be matched")
ap.add_argument("-v", "--visualize",required=False,default=r"真彩色影像的路径")
ap.add_argument("-o", "--output",required=False,default=r"保存路径")
args = vars(ap.parse_args())

# put the thermal image in a folder named thermal and the visible image in a folder named visible with the same name
# load the image image, convert it to grayscale, and detect edges
template = cv2.imread(args["image"])
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
template = cv2.Canny(template, 50, 200)
(tH, tW) = template.shape[:2]
cv2.imshow("Template", template)
#cv2.waitKey(0)

# loop over the images to find the template in

# load the image, convert it to grayscale, and initialize the
# bookkeeping variable to keep track of the matched region
image = cv2.imread(args["visualize"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
found = None

# loop over the scales of the image
for scale in np.linspace(0.2, 1.0, 20)[::-1]:
    # resize the image according to the scale, and keep track
    # of the ratio of the resizing
    resized = cv2.resize(gray, (int(gray.shape[1] * scale),int(gray.shape[0] * scale)))
    r = gray.shape[1] / float(resized.shape[1])

    # if the resized image is smaller than the template, then break
    # from the loop
    if resized.shape[0] < tH or resized.shape[1] < tW:
        break

    # detect edges in the resized, grayscale image and apply template
    # matching to find the template in the image
    edged = cv2.Canny(resized, 50, 200)
    result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF)
    (_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)

    # check to see if the iteration should be visualized
    if True:
        # draw a bounding box around the detected region
        clone = np.dstack([edged, edged, edged])
        cv2.rectangle(clone, (maxLoc[0], maxLoc[1]),
            (maxLoc[0] + tW, maxLoc[1] + tH), (0, 0, 255), 2)
        cv2.imshow("Visualize", clone)
        #cv2.waitKey(0)

    # if we have found a new maximum correlation value, then update
    # the bookkeeping variable
    if found is None or maxVal > found[0]:
        found = (maxVal, maxLoc, r)

# unpack the bookkeeping variable and compute the (x, y) coordinates
# of the bounding box based on the resized ratio
(_, 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))

# draw a bounding box around the detected result and display the image
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)

#name = r"E:\temp\data5/thermal/"+args["image"]+'.JPG'
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]))

#cropped image will be saved in a folder named output
if os.path.exists(os.path.join(args["output"],"process")):
   pass
else:
   os.mkdir(os.path.join(args["output"],"process"))
cv2.imwrite(os.path.join(args["output"],"process", os.path.basename(args["visualize"])),crop_img)

#both images are concatenated and saved in a folder named results
final = np.concatenate((crop_img, thermal_image), axis = 1)
if os.path.exists(os.path.join(args["output"],"results")):
   pass
else:
   os.mkdir(os.path.join(args["output"],"results"))
cv2.imwrite(os.path.join(args["output"],"results", os.path.basename(args["visualize"])),final)

#cv2.waitKey(0)
# Registration
# Read reference image
refFilename =  args["image"]
print("Reading reference image : ", refFilename)
imReference = cv2.imread(refFilename, cv2.IMREAD_COLOR)

# Read image to be aligned
imFilename = os.path.join(args["output"],"process", os.path.basename(args["visualize"]))
print("Reading image to align : ", imFilename);  
im = cv2.imread(imFilename, cv2.IMREAD_COLOR)
file_name=os.path.basename(args["image"])+'_registration.JPG'
imReg, h = alignImages(im,imReference,file_name)
cv2.imwrite(os.path.join(args["output"],"results", os.path.basename(args["image"])+'_result.JPG'),imReg)
print("Estimated homography : \n",  h)

我们已经成功地进行了热到可见图像配准。你可以用你的数据集来尝试一下,然后看看结果。

后续:

        因opencv版本问题做了修改,最终结果可以在registration和result保存路径下查看,其中opencv原因需要英文路径,调用使用方法如下:

python .\main.py -i “热红外影像路径” -v “真彩色影像路径” -o “保存路径”

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

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

相关文章

高薪!【YesPMP】众包平台5月9日最新外包项目

【YesPMP】众包平台5月9日最新外包项目&#xff0c;感兴趣的小伙伴&#xff0c;可进入平台参与竞标&#xff0c;竞标后与项目方直接与联系&#xff0c;双方直接对接。 1.查看项目&#xff1a;go编写的协议网关成品代码(支持modbus,knx等) http:// https://www.yespmp.com/proj…

HTTPS 是如何进行安全传输的 ?

概述 现代密码学对信息的处理主要离不开以下的三种形式&#xff1a; 摘要&#xff1a;主要用于数据校验&#xff0c;例如存储密码等&#xff0c;摘要是对信息进行单向的哈希&#xff0c;改变信息的原有形态&#xff0c;因为哈希函数的特点是易变性&#xff08;即使微小的变化也…

医学四种概念:B超、X光、CT、核磁共振

辐射检测&#xff1a;CT和X光 X光&#xff1a;X光检测价格低、时间短、出片快、辐射小&#xff0c;适合前期检查。由于人体各个组织对X线所产生的影响是不同的&#xff0c;所以就有不同的反应实验就是下图 生成的图片为&#xff0c;它把三维的你压缩成二维的图片了&#xff0c…

上位机图像处理和嵌入式模块部署(树莓派4b和mcu的分工与配合)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 树莓派4b从广义上来说&#xff0c;它本身就是一个mini小电脑。我们需要什么软件&#xff0c;就可以apt install去下载即可。这和之前嵌入式linux开…

探索设计模式的魅力:权力集中,效率提升,中心化模式的优势与挑战

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索中心化模式之旅✨ 大家好啊&#xff01;&#x1f44b; 这次我们要聊的是IT界一…

matlab使用教程(66)—在图中绘制多条曲线(2019b以下版本)

您可以采用多种方式合并绘图。利用子图&#xff0c;可在同一坐标区中合并多个图&#xff0c;或在一个图窗中创建多个坐标区。 1.在同一坐标区中合并绘图 默认情况下&#xff0c;新图将清除现有图&#xff0c;并重置标题等坐标区属性。但是&#xff0c;您可以使用 hold on 命令…

Netty HTTP2 示例-响应式编程-013

🤗 ApiHug {Postman|Swagger|Api...} = 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱,有温度,有质量,有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace The Next Generation API Development Platform …

数据结构复习指导之二叉树的概念

文章目录 二叉树 考纲内容 复习提示 1.二叉树的概念 1.1二叉树的定义及其主要特性 1.1.1二叉树的定义 1.1.2几种特殊的二叉树 1.1.3二叉树的性质 1.2二叉树的存储结构 1.2.1顺序存储结构 1.2.2链式存储结构 知识回顾 二叉树 考纲内容 &#xff08;一&#xff09;树…

Rust 使用egui创建一个简单的下载器demo

仓库连接: https://github.com/GaN601/egui-demo-download-util 这是我第一个rust gui demo, 学习rust有挺长时间了, 但是一直没有落实到实践中, 本着对桌面应用的兴趣, 考察了slint、egui两种框架, 最后还是选择了egui. 这篇博客同时包含我当前的一些理解, 但是自身技术有限,…

中职大数据专业介绍:大数据技术应用

近年来&#xff0c;人工智能在经济发展、社会进步、国际政治经济格局等方面已经产生重大而深远的影响。规划纲要对“十四五”及未来十余年我国人工智能的发展目标、核心技术突破、智能化转型与应用&#xff0c;以及保障措施等多个方面都作出了部署。 据2020年全国教育事业发展统…

Python - 金三银四心路历程 之 数据结构与算法 刷题

目录 一.引言 二.心路历程 三.刷题经历 四.刷题历程 五.总结 一.引言 <夜深人静写算法> 是 23 年 12 月底博主打算跳槽时开始做刷题准备做的专栏&#xff0c;前后准备了大约一个月&#xff0c;刷题完毕后简单准备了项目和简历后就开始加入找工作大军了&#xff0c;最…

【DevOps】Jenkins 集成Docker

目录 1. 安装 Docker 和 Jenkins 2. 在 Jenkins 中安装 Docker 插件 3. 配置 Docker 连接 4. 创建 Jenkins Pipeline 5. 示例 Pipeline 脚本 6. 运行 Jenkins Job 7. 扩展功能 8、docker配置测试连接的时候报错处理 将 Docker 与 Jenkins 集成可以实现持续集成和持续交…

介绍 ffmpeg.dll 文件以及ffmpeg.dll丢失怎么办的五种修复方法

ffmpeg.dll 是一个动态链接库文件&#xff0c;属于 FFmpeg运行库。它在计算机上扮演着非常重要的角色&#xff0c;因为它提供了许多应用程序和操作系统所需的功能和组件。当 ffmpeg.dll 文件丢失或损坏时&#xff0c;可能会导致程序无法正常运行&#xff0c;甚至系统崩溃。下面…

box-decoration-break 使用介绍

box-decoration-break属性的使用 一、定义 box-decoration-break是CSS片段模块&#xff08;CSS Fragmentation Module Level 3&#xff09;中的一个属性&#xff0c;主要用于指定背景&#xff08;background&#xff09;、内边距&#xff08;padding&#xff09;、边框&#…

Flink container exit 143 问题排查

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

Flask SQLAlchemy 技术指南

文章目录 什么是 Flask SQLAlchemy&#xff1f;安装 Flask SQLAlchemy创建 Flask 应用和数据库模型添加和查询数据运行 Flask 应用总结**数据库迁移&#xff08;Database Migrations&#xff09;****复杂查询****关系模型****事务处理****性能优化****安全性****扩展功能** Fla…

【2024高校网络安全管理运维赛】巨细记录!

2024高校网络安全管理运维赛 文章目录 2024高校网络安全管理运维赛MISC签到考点&#xff1a;动态图片分帧提取 easyshell考点&#xff1a;流量分析 冰蝎3.0 Webphpsql考点&#xff1a;sql万能钥匙 fileit考点&#xff1a;xml注入 外带 Cryptosecretbit考点&#xff1a;代码阅读…

Pyecharts的编程环境准备

一&#xff0c;准备Python编程环境&#xff1a; Python版本&#xff1a;3.10以上&#xff0c;最高版本3.12 https://www.python.org/ 进入官网&#xff0c;点击downloads—>windows进入下载页面&#xff0c;搜索”3.10.6”找到指定版本&#xff0c;下载并安装64位Installer…

可视化-实验四- seaborn工具包绘图基础及关系

一、任务一 1.1 开发环境 多种选择方案&#xff08;大家根据自己的编程习惯&#xff0c;选择适合自己的工具&#xff09;&#xff0c;老师授课如下&#xff1a;Anaconda3Jupter 1.2 特殊包 导入工具包设置中文显示&#xff1a; import matplotlib.pyplot as plt import p…

HTTP常见面试题(二)

3.1 HTTP 常见面试题 HTTP特性 HTTP 常见到版本有 HTTP/1.1&#xff0c;HTTP/2.0&#xff0c;HTTP/3.0&#xff0c;不同版本的 HTTP 特性是不一样的。 HTTP/1.1 的优点有哪些&#xff1f; HTTP 最突出的优点是「简单、灵活和易于扩展、应用广泛和跨平台」。 1. 简单 HTTP…