OpenCV多幅图像合为一幅图像

在使用 OpenCV 显示图片时,一个窗口只能显示一幅图片,且不便于给图片添加标题,因此在需要显示多个图像并进行比较的情况下不太方便。使用 PIL 可以显示多个图片并添加标题,但鉴于使用 OpenCV时还要专门用 PIL 把 BGR 转为 RGB 并显示图像,简直是简直了!!!于是使用 OpenCV 和 numpy 写了两个函数:
ImgReplace(ImgA,ImgB,Position)用于将图片 ImgB 粘贴到 ImgA 的 position 位置处,并返回处理过的图像。ImgB的尺寸必须小于ImgA。ImgShow(Img,Layout,Title='',Text=[''],Scaling=1,Bk_color=(0,0,0),Font_size=0.7,Font_thick=1,Font_color=(255,255,255))用于将多幅图像合为一幅图像,并为合成图像和各个小图像添加标题。多个小图像的尺寸可以不同,小图像之间横向最小距离20像素,纵向最小距离50像素。函数共有9个参数,其中有两个参数 Img 和 Layout 是必要参数,其它参数可默认,详细参数说明见代码。

  1. ShowImg.py:
# -*- coding: utf-8 -*-
"""
Created on Tue Oct 15 21:27:29 2019

@author: Belth Pixtink

filename:ShowImg.py
******************************************************************************
ImgReplace(ImgA,ImgB,Position)
用途:将ImgB贴到ImgA的指定位置
ImgA:主图像
ImgB;需要拷贝的图像,尺寸应小于ImgA
Position:粘贴到ImgA中的位置
******************************************************************************
ImgShow(Img,Layout,Title='',Text=[''],Scaling=1,Bk_color=(255,255,255),
Font_size=0.7,Font_thick=1,Font_color=(0,0,0))
用途:将多幅图像合成为一幅图像
Img:必要参数,带合成的图像列表:Img[Img1,Img2,...]
Layout:必要参数,图像的排列方式,Layout[c,r],c:横向图片数量,r:纵向图片数量
Title:合成的主图像标题,上方正中显示,不支持汉字显示,默认无主标题
Text:每幅子图像的标题,列表形式:Text[Text1,Text2...],不支持汉字显示,默认无子标题
Scaling:合成图像的缩放因子,默认为1,不缩放
Bk_color:主图像的颜色,即合成后图像的背景色,元组形式:(B,G,R),默认为(0,0,0),黑色
Font_size:标题字体大小,取值范围0~1.2,默认为0.7
Font_thick:标题字体粗细,取值范围1~6,默认为1
Font_color:标题字体颜色,元组形式:(B,G,R),默认为(255,255,255),白色
******************************************************************************
"""

import cv2
import numpy as np

def ImgReplace(ImgA,ImgB,Position):
     X_size=ImgB.shape[0]
     Y_size=ImgB.shape[1]
     if ImgA.shape[0]>X_size and ImgA.shape[1]>Y_size:
          roi=ImgA[Position[1]:Position[1]+X_size,Position[0]:Position[0]+Y_size]
          gray=cv2.cvtColor(ImgB, cv2.COLOR_BGR2GRAY)
          ret, mask = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
          mask_inv = cv2.bitwise_not(mask)
          img = cv2.bitwise_and(roi, roi, mask=mask_inv)
          dst = cv2.add(img,ImgB)
          ImgA[Position[1]:Position[1]+X_size,Position[0]:Position[0]+Y_size] = dst
     else:
          print('ERROR: The size of ImgA should be larger than ImgB!!!')
     return ImgA

def ImgShow(Img,Layout,Title='',Text=[''],Scaling=1,Bk_color=(0,0,0),Font_size=0.7,Font_thick=1,Font_color=(255,255,255)):
     x = list()
     y = list()
     H_interval = list()
     W_interval = list()
     Width = 0
     Height = 0
     PicNum = len(Img)
     if Text[0]=='' and len(Text) == 1:
          Text = Text*PicNum
     elif len(Text) < PicNum:
          for i in range(len(Text),PicNum):
               Text.append('')
     if Font_size > 1.2:
          Font_size = 1.2
     if Font_thick > 6:
          Font_thick = 6
     for i in range(0,PicNum,1):
          x.append(Img[i].shape[1])
          y.append(Img[i].shape[0])
     for i in range(PicNum,Layout[0]*Layout[1],1):
          x.append(0)
          y.append(0)
     for i in range(0,Layout[1]):
          Height = Height + max(y[i*Layout[0]:i*Layout[0]+Layout[0]:])
          H_interval.append(Height)
     for i in range(0,Layout[0]):
          Width = Width + max(x[i::Layout[0]])
          W_interval.append(Width)
     Syn = np.zeros((Height+(Layout[1]+1)*50+20,Width+(Layout[0]+1)*20,3),np.uint8)
     cv2.rectangle(Syn,(0,0),(Syn.shape[1],Syn.shape[0]),Bk_color,-1)
     column = 20
     if Title == '':
          row = 50
     else:
          row = 100
          cv2.putText(Syn,Title,(int(Syn.shape[1]/2-(len(Title)*Font_size*1.5*18)/2),50),cv2.FONT_HERSHEY_SIMPLEX,Font_size*1.5,Font_color,Font_thick+1,cv2.LINE_AA)
     for i in range(0,Layout[1],1):
          for j in range(0,Layout[0],1):
               if i*Layout[0]+j < PicNum:
                    Syn = ImgReplace(Syn,Img[i*Layout[0]+j],[column,row])
                    cv2.putText(Syn,Text[i*Layout[0]+j],(column,row-5),cv2.FONT_HERSHEY_SIMPLEX,Font_size,Font_color,Font_thick,cv2.LINE_AA)
                    column = W_interval[j]+20*(j+2)
          row = row+max(y[Layout[0]*i:Layout[0]*(i+1):])+50
          column = 20
     if Scaling != 1:
          Syn = cv2.resize(Syn,(int(Syn.shape[1]*Scaling),int(Syn.shape[0]*Scaling)),interpolation = cv2.INTER_AREA)
     return Syn
  1. 调用 ImgShow :
# -*- coding: utf-8 -*-
"""
Created on Mon Oct 14 21:51:54 2019

@author: Belth Pixtink
"""
import cv2
import numpy as np
import ImgShow

print('Start...')
Pic=cv2.imread('D:/Pictures/ET.png')
PicM = cv2.resize(Pic,(480,270),interpolation = cv2.INTER_AREA)

Ck1 = np.array([[ -1,-1, 0],
                [ -1, 0, 1],
                [  0, 1, 1]])
Ck2 = np.array([[-1,1,-1],
                [ 1,0, 1],
                [-1,1,-1]])
Ck3 = np.array([[ 1, 1,1],
                [ 1,-8,1],
                [ 1, 1,1]])
Ck4 = np.array([[0.3,0.1,0.4],
                [0.5, 0,-0.5],
                [-0.4,-0.1,-0.3]])
Ck5 = np.array([[0,0,-1,0,0],
                [0,0,-1,0,0],
                [0,0, 2,0,0],
                [0,0, 0,0,0],
                [0,0, 0,0,0]])
#共计六幅图片
PicConv1 = cv2.filter2D(PicM,-1,Ck1)
PicConv2 = cv2.filter2D(PicM,-1,Ck2)
PicConv3 = cv2.filter2D(PicM,-1,Ck3)
PicConv4 = cv2.filter2D(PicM,-1,Ck4)
PicConv5 = cv2.filter2D(PicM,-1,Ck5)
#修改图片尺寸以测试函数
PicConv1 = cv2.resize(PicConv1,(510,390),interpolation = cv2.INTER_AREA)
PicConv2 = cv2.resize(PicConv2,(640,360),interpolation = cv2.INTER_AREA)
PicConv3 = cv2.resize(PicConv3,(720,400),interpolation = cv2.INTER_AREA)
PicConv4 = cv2.resize(PicConv4,(360,200),interpolation = cv2.INTER_AREA)
PicConv5 = cv2.resize(PicConv5,(480,270),interpolation = cv2.INTER_AREA)

T = ['Ck0','Ck1','Ck2','Ck3','Ck4','Ck5']
IMG = ImgShow.ImgShow([PicM,PicConv1,PicConv2,PicConv3,PicConv4,PicConv5],[3,2],Text=T,Title='Pictures',Scaling=1,Font_size=0.9,Font_thick=3,Font_color = (255,0,128),Bk_color=(192,192,192))
cv2.imwrite('D:/Pictures/Test.png',IMG)
print('End...')

运行效果:

  1. 3x2排列:
    @BelthPixtink
  2. 4x2排列:
    @BelthPixtink
  3. 2x3排列:
    @BelthPixtink
    == --------------------------------------------------------华丽的分割线--------------------------------------------------------==
<think>好的,我现在需要帮助用户解决如何使用VB.NET实现OpenCV多幅图像拼接算法的问题。用户还提到了示例代码和教程,所以我得先理清楚OpenCV在VB.NET中的使用方式,尤其是EmguCV这个库,因为它是.NET平台下的OpenCV封装。 首先,我需要确认用户提到的引用内容。用户提供的引用[1]、[2]、[3]都是关于EmguCV中加载图像的不同方法,使用Image和Mat类。这说明用户可能已经对EmguCV有一定的了解,但需要进一步的指导来实现图像拼接。引用[4]和[5]讨论了图像拼接的传统步骤和特征匹配,这帮助我确认图像拼接的基本流程:特征提取、匹配、配准、接缝查找和混合。 接下来,我需要考虑如何在VB.NET中实现这些步骤。EmguCV提供了许多计算机视觉的功能,比如特征检测可以使用SIFT、SURF或ORB,匹配可以使用FLANN或BFMatcher。然后,需要利用这些特征点找到单应性矩阵进行图像配准,接着进行图像融合。 用户可能需要具体的代码示例,所以我得回忆EmguCV的相关类和方法。例如,使用Features2D模块检测特征点和描述子,使用Features2D.DrawMatches来可视化匹配点。然后,使用Matcher进行特征匹配,接着用HomographyFinder.FindHomography计算单应矩阵。最后,使用Warper进行图像配准,并用SeamFinder和Blender处理接缝和混合。 需要注意的是,VB.NET的语法和C#有所不同,所以代码示例需要符合VB.NET的结构。例如,变量的声明和方法的调用方式。同时,用户可能需要处理多张图像的拼接,而不仅仅是两张,这会增加复杂度,可能需要使用类似Stitcher类的高级接口,但EmguCV的Stitcher类可能需要更多的配置和兼容性检查。 另外,引用[5]中提到两两匹配特征数保存在matchscores数组,这可能涉及到如何确定图像之间的连接顺序,构建图像关系图,然后进行全景拼接。这部分可能需要更复杂的逻辑,比如确定参考图像,逐步拼接其他图像。 我需要分步骤解释整个流程,并提供关键代码段,比如特征检测、匹配、单应性矩阵计算和图像变形。同时,提醒用户注意图像加载路径、异常处理以及可能的性能问题,比如处理大图像时的内存管理。 最后,考虑到用户可能需要实际可运行的代码,我应该建议参考EmguCV的官方文档和示例,确保代码的准确性。如果有现成的Stitcher类可用,可以优先推荐,因为它封装了复杂的步骤,但也要说明其限制和可能需要的参数调整。</think>以下为使用VB.NET结合EmguCV实现多图拼接的详细步骤和示例代码: ### 一、环境准备 1. 安装EmguCV 4.x(需对应OpenCV 4.x版本) 2. 添加Emgu.CV、Emgu.CV.Bitmap、Emgu.CV.runtime.windows等NuGet包 3. 引用命名空间: ```vb Imports Emgu.CV Imports Emgu.CV.CvEnum Imports Emgu.CV.Features2D Imports Emgu.CV.Stitching Imports Emgu.CV.Util ``` ### 二、核心实现步骤 #### 1. 图像加载与预处理 ```vb Dim images As New List(Of Mat)() images.Add(New Mat("image1.jpg", ImreadModes.Color)) images.Add(New Mat("image2.jpg", ImreadModes.Color)) ' 确保所有图像色彩空间一致 CvInvoke.CvtColor(images(0), images(0), ColorConversion.Bgr2Rgb) ``` #### 2. 特征检测与匹配 ```vb Dim detector As New SIFT(1000) Dim matcher As New BFMatcher(DistanceType.L2) Dim keypoints As New VectorOfKeyPoint() Dim descriptors As New Mat() detector.DetectAndCompute(images(0), Nothing, keypoints, descriptors, False) ' 对每对图像执行特征匹配 Dim matches As New VectorOfDMatch() matcher.Match(descriptors1, descriptors2, matches) ``` #### 3. 单应性矩阵计算 ```vb Dim homography As New Mat() Dim mask As New Mat() Dim inliersCount As Integer = CvInvoke.FindHomography( srcPoints, dstPoints, homography, RobustEstimationAlgorithm.Ransac, 3.0, mask) ``` #### 4. 图像拼接与融合 ```vb Dim stitcher As New Stitcher(Stitcher.Mode.Scans) Dim panorama As New Mat() Dim status As Stitcher.Status = stitcher.Stitch(images, panorama) If status = Stitcher.Status.Ok Then CvInvoke.Imwrite("result.jpg", panorama) End If ``` ### 三、完整示例代码 ```vb Public Sub ImageStitching() Try Dim imgPaths As String() = {"1.jpg", "2.jpg", "3.jpg"} Dim mats As New VectorOfMat() For Each path In imgPaths Using m As New Mat(path, ImreadModes.Color) mats.Push(m) End Using Next Dim stitcher As New Stitcher(Stitcher.Mode.Panorama) Dim result As New Mat() Dim status As Stitcher.Status = stitcher.Stitch(mats, result) If status = Stitcher.Status.Ok Then CvInvoke.Imwrite("panorama_result.jpg", result) MessageBox.Show("拼接成功") Else MessageBox.Show($"拼接失败,错误代码:{status}") End If Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub ``` ### 四、关键优化点 1. **特征检测优化**: - 使用$AKAZE$算法替代$SIFT$提升速度 - 设置$MaxFeatures$参数控制特征点数量 2. **融合参数调整**: ```vb stitcher.SetBlender(New FeatherBlender(0.5)) ' 羽化混合参数 stitcher.SetSeamFinder(New VoronoiSeamFinder()) ' 接缝查找算法 ``` 3. **内存管理**: ```vb Using warpResult As New UMat() CvInvoke.WarpPerspective(srcImage, warpResult, homography, dstSize) End Using ``` ### 五、常见问题处理 1. **图像错位问题**: - 检查特征匹配正确率(RANSAC内点数量) - 验证单应性矩阵条件数:$$ \text{cond}(H) < 10^5 $$ 2. **色差问题**: ```vb Dim compensator As New GainCompensator() compensator.Apply(0, New[] { Color.Black }, images, masks) ``` [^1]: 引用EmguCV图像加载基础 [^4]: 传统拼接流程参考 [^5]: 特征匹配实现原理
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值