简单的图片拼接

图片能够拼接的前提是:两幅图片的边缘有重叠的部分

在CSDN上看到一篇关于《图像拼接原理》的博客,讲的不错。

拼接思路简述

使用Hu矩匹配两幅图片的指定区域,符合条件则记录该像素或模板的位置,供拼接时使用。

程序:

#include "stdafx.h"
#include <iostream>
#include <highgui.h>
#include "cv.h"
#include <vector>
#include <functional>

using namespace std;
using namespace cv;

struct MatchR
{
    int  PositionX;    //存储位置的X坐标
    double MResult;    //存储轮廓匹配结果
    bool operator < (const MatchR& rhs) const   //升序排序时必须写的函数
    {   
        return MResult < rhs.MResult; 
    }
};

vector<MatchR> vec;

//获取输入图像的轮廓
CvSeq* getImageContour(IplImage* srcIn);

int main(int argc, char* argv[])
{
    const char * LeftPath="leftpic.bmp";
    const char * RightPath="rightpic.bmp";
    
    IplImage * Lpic=cvLoadImage(LeftPath,CV_LOAD_IMAGE_GRAYSCALE);
    IplImage * Rpic=cvLoadImage(RightPath,CV_LOAD_IMAGE_GRAYSCALE);

    assert(Lpic && Rpic);

    //选取左图的一部分作为兴趣区域
    const int TemplWi=(int)(Lpic->width)/10;
    CvRect RectROI=cvRect((Lpic->width-TemplWi),0,TemplWi,Lpic->height);

    //准备模板图像ImgTemplt
    cvSetImageROI(Lpic,RectROI);
    IplImage * ImgTemplt=cvCreateImage(cvSize(TemplWi,Lpic->height),Lpic->depth,1);
    cvCopy(Lpic,ImgTemplt,NULL);
    cvResetImageROI(Lpic);    
    
    //获取图像1的轮廓
    CvSeq* contour1;
    contour1 = getImageContour(ImgTemplt);

    //循环计算右图特定区域的轮廓与模板图像contour1对比        
    IplImage * TempImg=cvCreateImage(cvSize(TemplWi,Rpic->height),Rpic->depth,1);//临时图像
    for(int i=0;i<(int)(Rpic->width-TemplWi)/10;++i)
    {
        CvRect rROI =cvRect(i,0,TemplWi,Rpic->height);
        cvSetImageROI(Rpic,rROI);
        cvCopy(Rpic,TempImg,NULL);
        cvResetImageROI(Rpic);        
        
        //获取图像2的轮廓
        CvSeq* contour2;
        contour2 = getImageContour(TempImg);

        MatchR resultS;
        resultS.PositionX=i;
        //计算匹配程度
        resultS.MResult=cvMatchShapes(contour1,contour2,1);
        
        vec.push_back(resultS);
        //释放轮廓存储空间
        cvReleaseMemStorage(&contour2->storage);
    }

    CvPoint StartPt;
    //排序找出vector中MResult最小的元素
    sort(vec.begin(),vec.end());

    StartPt.x=vec[0].PositionX+TemplWi;
    StartPt.y=0;

    //加载原图
    IplImage * LpicColor=cvLoadImage(LeftPath,CV_LOAD_IMAGE_COLOR);
    IplImage * RpicColor=cvLoadImage(RightPath,CV_LOAD_IMAGE_COLOR);

    //创建长度宽度合适的图像ResukltImage作拼接用
    int StitchImgWidth=LpicColor->width+(RpicColor->width-StartPt.x);
    IplImage * ResukltImage=cvCreateImage(cvSize(StitchImgWidth,LpicColor->height),LpicColor->depth,LpicColor->nChannels);

    //将左图复制到ResukltImage中
    CvRect ROI1=cvRect(0,0,LpicColor->width,LpicColor->height);
    cvSetImageROI(ResukltImage,ROI1);
    cvCopy(LpicColor,ResukltImage);
    cvResetImageROI(ResukltImage);

    //将右图的以StartPt为左上角的区域复制到ResukltImage的右侧剩余部分
    ROI1=cvRect(LpicColor->width,0,(ResukltImage->width-LpicColor->width),RpicColor->height);
    cvSetImageROI(ResukltImage,ROI1);

    CvRect ROI2=cvRect(StartPt.x,0,RpicColor->width-StartPt.x,RpicColor->height);
    cvSetImageROI(RpicColor,ROI2);
    cvCopy(RpicColor,ResukltImage,NULL);
    cvResetImageROI(RpicColor);
    cvResetImageROI(ResukltImage);

    //创建窗口显示拼接结果
    cvNamedWindow("拼接后图像",0);    
    cvShowImage("拼接后图像",ResukltImage);

    cvWaitKey(0);

    //释放轮廓存储空间
    cvReleaseMemStorage(&contour1->storage);
    //释放图像
    cvReleaseImage(&Lpic);
    cvReleaseImage(&Rpic);
    cvReleaseImage(&ImgTemplt);
    cvReleaseImage(&TempImg);
    cvReleaseImage(&ResukltImage);
    cvReleaseImage(&LpicColor);
    cvReleaseImage(&RpicColor);
    //销毁窗口
    cvDestroyWindow("拼接后图像");
    
    return 0;
}

/// <summary>
/// 函数功能:获取输入图像的轮廓
/// </summary>
/// <param name="srcIn"></param>
/// <returns>CvSeq* : 存储轮廓信息</returns>
CvSeq* getImageContour(IplImage* srcIn)
{
    IplImage* src;
    src = cvCreateImage(cvGetSize(srcIn),8,1);
    
    //拷贝图像 
    cvCopy(srcIn,src);

    //创建空间
    CvMemStorage* mem = cvCreateMemStorage(0);
    CvSeq* seq;

    if(!mem)
    {
        printf("mem is null");
    }

    //二值化图像
    cvThreshold(src,src,100,255,0);
    //cvCanny(src,src,15,30,3);

    //计算图像轮廓
    cvFindContours(src,mem,&seq,sizeof(CvContour),CV_RETR_CCOMP);

    //释放图像空间
    cvReleaseImage(&src);    

    //返回轮廓信息
    return seq;
}

待拼接的图像左图-->leftpic:

待拼接的图像右图-->rightpic:

结果图片:

 

  

‖==========钟于原创 乐于分享 宁静致远 毋忆典藏==========‖
原文地址:https://www.cnblogs.com/tingshuixuan2012/p/ImageStitching.html