当前位置:   article > 正文

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

红外可见光配准

一、前言

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

二、热红外数据介绍

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

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

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

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

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

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

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

三、配准过程

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

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

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

图4 最终输出结果

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

  1. from __future__ import print_function
  2. import numpy as np
  3. import argparse
  4. import glob
  5. import cv2
  6. import os
  7. MAX_FEATURES = 500
  8. GOOD_MATCH_PERCENT = 0.15
  9. #function to align the thermal and visible image, it returns the homography matrix
  10. def alignImages(im1, im2,filename):
  11. # Convert images to grayscale
  12. im1Gray = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY)
  13. im2Gray = cv2.cvtColor(im2, cv2.COLOR_BGR2GRAY)
  14. # Detect ORB features and compute descriptors.
  15. orb = cv2.ORB_create(MAX_FEATURES)
  16. keypoints1, descriptors1 = orb.detectAndCompute(im1Gray, None)
  17. keypoints2, descriptors2 = orb.detectAndCompute(im2Gray, None)
  18. # Match features.
  19. matcher = cv2.DescriptorMatcher_create(cv2.DESCRIPTOR_MATCHER_BRUTEFORCE_HAMMING)
  20. matches = matcher.match(descriptors1, descriptors2, None)
  21. # Sort matches by score
  22. matches.sort(key=lambda x: x.distance, reverse=False)
  23. # Remove not so good matches
  24. numGoodMatches = int(len(matches) * GOOD_MATCH_PERCENT)
  25. matches = matches[:numGoodMatches]
  26. # Draw top matches
  27. imMatches = cv2.drawMatches(im1, keypoints1, im2, keypoints2, matches, None)
  28. if os.path.exists(os.path.join(args["output"],"registration")):
  29. pass
  30. else:
  31. os.mkdir(os.path.join(args["output"],"registration"))
  32. cv2.imwrite(os.path.join(args["output"],"registration",filename), imMatches)
  33. # Extract location of good matches
  34. points1 = np.zeros((len(matches), 2), dtype=np.float32)
  35. points2 = np.zeros((len(matches), 2), dtype=np.float32)
  36. for i, match in enumerate(matches):
  37. points1[i, :] = keypoints1[match.queryIdx].pt
  38. points2[i, :] = keypoints2[match.trainIdx].pt
  39. # Find homography
  40. h, mask = cv2.findHomography(points1, points2, cv2.RANSAC)
  41. # Use homography
  42. height, width, channels = im2.shape
  43. im1Reg = cv2.warpPerspective(im1, h, (width, height))
  44. return im1Reg, h
  45. # construct the argument parser and parse the arguments
  46. # run the file with python registration.py --image filename
  47. ap = argparse.ArgumentParser()
  48. # ap.add_argument("-t", "--template", required=True, help="Path to template image")
  49. ap.add_argument("-i", "--image", required=False,default=r"热红外图像的路径",
  50. help="Path to images where thermal template will be matched")
  51. ap.add_argument("-v", "--visualize",required=False,default=r"真彩色影像的路径")
  52. ap.add_argument("-o", "--output",required=False,default=r"保存路径")
  53. args = vars(ap.parse_args())
  54. # put the thermal image in a folder named thermal and the visible image in a folder named visible with the same name
  55. # load the image image, convert it to grayscale, and detect edges
  56. template = cv2.imread(args["image"])
  57. template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
  58. template = cv2.Canny(template, 50, 200)
  59. (tH, tW) = template.shape[:2]
  60. cv2.imshow("Template", template)
  61. #cv2.waitKey(0)
  62. # loop over the images to find the template in
  63. # load the image, convert it to grayscale, and initialize the
  64. # bookkeeping variable to keep track of the matched region
  65. image = cv2.imread(args["visualize"])
  66. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  67. found = None
  68. # loop over the scales of the image
  69. for scale in np.linspace(0.2, 1.0, 20)[::-1]:
  70. # resize the image according to the scale, and keep track
  71. # of the ratio of the resizing
  72. resized = cv2.resize(gray, (int(gray.shape[1] * scale),int(gray.shape[0] * scale)))
  73. r = gray.shape[1] / float(resized.shape[1])
  74. # if the resized image is smaller than the template, then break
  75. # from the loop
  76. if resized.shape[0] < tH or resized.shape[1] < tW:
  77. break
  78. # detect edges in the resized, grayscale image and apply template
  79. # matching to find the template in the image
  80. edged = cv2.Canny(resized, 50, 200)
  81. result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF)
  82. (_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)
  83. # check to see if the iteration should be visualized
  84. if True:
  85. # draw a bounding box around the detected region
  86. clone = np.dstack([edged, edged, edged])
  87. cv2.rectangle(clone, (maxLoc[0], maxLoc[1]),
  88. (maxLoc[0] + tW, maxLoc[1] + tH), (0, 0, 255), 2)
  89. cv2.imshow("Visualize", clone)
  90. #cv2.waitKey(0)
  91. # if we have found a new maximum correlation value, then update
  92. # the bookkeeping variable
  93. if found is None or maxVal > found[0]:
  94. found = (maxVal, maxLoc, r)
  95. # unpack the bookkeeping variable and compute the (x, y) coordinates
  96. # of the bounding box based on the resized ratio
  97. (_, maxLoc, r) = found
  98. (startX, startY) = (int(maxLoc[0] * r), int(maxLoc[1] * r))
  99. (endX, endY) = (int((maxLoc[0] + tW) * r), int((maxLoc[1] + tH) * r))
  100. # draw a bounding box around the detected result and display the image
  101. cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2)
  102. crop_img = image[startY:endY, startX:endX]
  103. #cv2.imshow("Image", image)
  104. cv2.imshow("Crop Image", crop_img)
  105. #cv2.waitKey(0)
  106. #name = r"E:\temp\data5/thermal/"+args["image"]+'.JPG'
  107. thermal_image = cv2.imread(args["image"], cv2.IMREAD_COLOR)
  108. #cropping out the matched part of the thermal image
  109. crop_img = cv2.resize(crop_img, (thermal_image.shape[1], thermal_image.shape[0]))
  110. #cropped image will be saved in a folder named output
  111. if os.path.exists(os.path.join(args["output"],"process")):
  112. pass
  113. else:
  114. os.mkdir(os.path.join(args["output"],"process"))
  115. cv2.imwrite(os.path.join(args["output"],"process", os.path.basename(args["visualize"])),crop_img)
  116. #both images are concatenated and saved in a folder named results
  117. final = np.concatenate((crop_img, thermal_image), axis = 1)
  118. if os.path.exists(os.path.join(args["output"],"results")):
  119. pass
  120. else:
  121. os.mkdir(os.path.join(args["output"],"results"))
  122. cv2.imwrite(os.path.join(args["output"],"results", os.path.basename(args["visualize"])),final)
  123. #cv2.waitKey(0)
  124. # Registration
  125. # Read reference image
  126. refFilename = args["image"]
  127. print("Reading reference image : ", refFilename)
  128. imReference = cv2.imread(refFilename, cv2.IMREAD_COLOR)
  129. # Read image to be aligned
  130. imFilename = os.path.join(args["output"],"process", os.path.basename(args["visualize"]))
  131. print("Reading image to align : ", imFilename);
  132. im = cv2.imread(imFilename, cv2.IMREAD_COLOR)
  133. file_name=os.path.basename(args["image"])+'_registration.JPG'
  134. imReg, h = alignImages(im,imReference,file_name)
  135. cv2.imwrite(os.path.join(args["output"],"results", os.path.basename(args["image"])+'_result.JPG'),imReg)
  136. print("Estimated homography : \n", h)

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

后续:

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/45251
推荐阅读
相关标签
  

闽ICP备14008679号