基于opencv的MFC多摄像机视场标定软件

一、项目需求

确定网络摄像机的监控视场在全景地图上的精确位置,并采用简单而高效的方法将其所在视场标定并投影到全景地图上,项目要求能够将多路网络摄像机的视场标定在全景地图上,并实现这样的功能:当调取当前摄像机视频播放时,其他摄像机处于暂停状态。

二、项目分析

1、如何将视频投影到全景地图上,实质上就是如何将一幅幅视频帧图像与全景图像进行配准,关于图像配准方面的研究已经有很多方法,本项目采用基于互信息的图像配准算法寻找四对精确特征匹配点对。

2、设计一个多摄像机视场标定的人机交互界面的软件系统,要求能够将多路网络摄像机的视场标定在全景地图上,并实现调取当前摄像机视频播放时,其他摄像机处于暂停状态。

三、最终软件界面设计如下:

四、部分代码如下:

// CamCalibrationDlg.h : 头文件
//

#pragma once
#include "cv.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/core.hpp>
#include "opencv2/calib3d/calib3d.hpp"
#include "highgui.h"
#include "cxcore.h"
#include "CvvImage.h"
#include <vector>
#include "afxwin.h"

using namespace cv;
using namespace std;

// CCamCalibrationDlg 对话框
class CCamCalibrationDlg : public CDialogEx
{
// 构造
public:
    CCamCalibrationDlg(CWnd* pParent = NULL);   // 标准构造函数

// 对话框数据
    enum { IDD = IDD_CAMCALIBRATION_DIALOG };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()

private:

    //全屏显示
    BOOL bFullScreen;
    CRect rectFullScreen;
    WINDOWPLACEMENT m_struOldWndpl;//结构中包含了有关窗口在屏幕上位置的信息
    WINDOWPLACEMENT m_struOldWndpPic;//PICTURE控件在屏幕上位置的信息

    vector<Point2f> m_newpoints; // 需要利用互信息子函数更新得到的匹配点集(要求四个)
    vector<Point2f> m_points1;// 视频帧图像匹配点集(要求四个)
    vector<Point2f> m_points2;// 全景图像匹配点集,初始匹配点集(要求四个)

    Mat TheImage; //全景图
    Mat CamImage; //视频帧图像

    CStatic m_TheImage;//是全景图界面的显示窗口
    CStatic m_CamImage;//是视频帧图像界面的显示窗口

    CRect m_TheImageRect;//显示全景窗口的矩形窗
    CRect m_CamImageRect;//显示视频窗口的矩形窗

    CString m_pt;    //与编辑框绑定的成员变量,将获取的点集中显示在编辑框中
    double  m_scale;    //全景图缩放比率

    CvCapture *capture;

    int g_m_run;  //视频暂停标志

    Mat H1; //投影变换矩阵1
    Mat H2; //投影变换矩阵2
    Mat H3; //投影变换矩阵3
    Mat H4; //投影变换矩阵4
    Mat H5; //投影变换矩阵5
    Mat H6; //投影变换矩阵6

    //存储投影后四个顶点的坐标
    vector<Point2f> m_pointsh1;
    vector<Point2f> m_pointsh2;
    vector<Point2f> m_pointsh3;
    vector<Point2f> m_pointsh4;
    vector<Point2f> m_pointsh5;
    vector<Point2f> m_pointsh6;

    int m_Radio; 

    int m_Pointdownflag;

public:

    void ShowMatImgToWnd(CWnd* pWnd, cv::Mat img);

    afx_msg void OnBnClickedPictureOpen();

    double Entropy(Mat img);//单幅图像信息熵计算

    double ComEntropy(Mat img1, Mat img2, double img1_entropy, double img2_entropy);// 两幅图像联合信息熵计算

    Point2f Refresh_MacthPoints(Point2f point1, Point2f point2);//查找全景图上四个精确匹配点集

    Point2f MousePointToImgPixel(Mat img, CRect rect, Point2f point);// 鼠标点击坐标转换为实际图像坐标《分辨率转换》

    afx_msg void OnBnClickedVideoPreview();
    afx_msg void OnBnClickedVideoPlay();
    afx_msg void OnBnClickedVideoPause();
    // afx_msg void OnTimer(UINT_PTR nIDEvent);

    afx_msg void OnBnClickedRadio1();
    afx_msg void OnBnClickedRadio2();
    afx_msg void OnBnClickedRadio3();
    afx_msg void OnBnClickedRadio4();
    afx_msg void OnBnClickedRadio5();
    afx_msg void OnBnClickedRadio6();

    afx_msg void OnBnClickedPictureChangeSize();
    afx_msg void OnBnClickedPicturePoints();
    afx_msg void OnBnClickedVideoPoints();
    afx_msg void OnBnClickedSavePoints();

    afx_msg void OnBnClickedAdjustPoints();

    afx_msg void OnBnClickedQuit();
    afx_msg void OnBnClickedHomgtaphyFind();
    afx_msg void OnBnClickedCalibration();

    Mat  showFinal(Mat src1, Mat src2); //将标定后的组合图显示出来
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

    ////全屏显示
    afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
    afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
    void drawpic(IplImage* img, unsigned int id);
    //绘图到&nbsp;MFC 的 Picture Control 控件相关函数
    //参数一为 OpenCV&nbsp;的图像数据结构类,参数二为 Picture Control 控件的id

};

// CamCalibrationDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "CamCalibration.h"
#include "CamCalibrationDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define   WIDTHBYTES(bits) (((bits)+31)/32*4)//用于使图像宽度所占字节数为4byte的倍数  

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);

}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// CCamCalibrationDlg 对话框

CCamCalibrationDlg::CCamCalibrationDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(CCamCalibrationDlg::IDD, pParent)

{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCamCalibrationDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);

    DDX_Control(pDX, IDC_PICTURE, m_TheImage);//自定义控件和IDC界面控件绑定
    DDX_Control(pDX, IDC_VIDEO, m_CamImage);//自定义控件和IDC界面控件绑定
    DDX_Text(pDX, IDC_EDIT_POINTSHOW, m_pt);//自定义控件和IDC编辑框绑定
    DDX_Text(pDX, IDC_EDIT_RESIZE, m_scale);//自定义控件和IDC编辑框绑定

}

BEGIN_MESSAGE_MAP(CCamCalibrationDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_PICTURE_OPEN, &CCamCalibrationDlg::OnBnClickedPictureOpen)
    ON_BN_CLICKED(IDC_VIDEO_PREVIEW, &CCamCalibrationDlg::OnBnClickedVideoPreview)
    ON_BN_CLICKED(IDC_VIDEO_PLAY, &CCamCalibrationDlg::OnBnClickedVideoPlay)
    ON_BN_CLICKED(IDC_VIDEO_PAUSE, &CCamCalibrationDlg::OnBnClickedVideoPause)
    // ON_WM_TIMER()

    ON_BN_CLICKED(IDC_RADIO1, &CCamCalibrationDlg::OnBnClickedRadio1)
    ON_BN_CLICKED(IDC_RADIO2, &CCamCalibrationDlg::OnBnClickedRadio2)
    ON_BN_CLICKED(IDC_RADIO3, &CCamCalibrationDlg::OnBnClickedRadio3)
    ON_BN_CLICKED(IDC_RADIO4, &CCamCalibrationDlg::OnBnClickedRadio4)
    ON_BN_CLICKED(IDC_RADIO5, &CCamCalibrationDlg::OnBnClickedRadio5)
    ON_BN_CLICKED(IDC_RADIO6, &CCamCalibrationDlg::OnBnClickedRadio6)
    ON_BN_CLICKED(IDC_PICTURE_CHANGE_SIZE, &CCamCalibrationDlg::OnBnClickedPictureChangeSize)
    ON_BN_CLICKED(IDC_PICTURE_POINTS, &CCamCalibrationDlg::OnBnClickedPicturePoints)
    ON_BN_CLICKED(IDC_VIDEO_POINTS, &CCamCalibrationDlg::OnBnClickedVideoPoints)
    ON_BN_CLICKED(IDC_ADJUST_POINTS, &CCamCalibrationDlg::OnBnClickedAdjustPoints)
    ON_BN_CLICKED(IDC_QUIT, &CCamCalibrationDlg::OnBnClickedQuit)
    ON_BN_CLICKED(IDC_HOMGTAPHY_FIND, &CCamCalibrationDlg::OnBnClickedHomgtaphyFind)
    ON_BN_CLICKED(IDC_CALIBRATION, &CCamCalibrationDlg::OnBnClickedCalibration)

    ON_WM_MOUSEMOVE()
    ON_WM_LBUTTONDOWN()

    ON_WM_LBUTTONDBLCLK()
    ON_WM_GETMINMAXINFO()
    ON_BN_CLICKED(IDC_SAVE_POINTS, &CCamCalibrationDlg::OnBnClickedSavePoints)
END_MESSAGE_MAP()

// CCamCalibrationDlg 消息处理程序

BOOL CCamCalibrationDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);         // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    ShowWindow(SW_MAXIMIZE);

    // TODO:  在此添加额外的初始化代码

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CCamCalibrationDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CCamCalibrationDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCamCalibrationDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}

// 将图像显示到对应的图像框
void CCamCalibrationDlg::ShowMatImgToWnd(CWnd* pWnd, cv::Mat img)
{
    if (img.empty())
        return;
    CDC *pDC = pWnd->GetDC();
    HDC hDC = pDC->GetSafeHdc();
    CRect rect;
    pWnd->GetClientRect(&rect);
    IplImage Iimg = img;
    CvvImage cimg;
    cimg.CopyOf(&Iimg); // 复制图片
    cimg.DrawToHDC(hDC, &rect); // 将图片绘制到显示控件的指定区域内
    ReleaseDC(pDC);
}

void CCamCalibrationDlg::OnBnClickedPictureOpen()
{
    // TODO:  在此添加控件通知处理程序代码
    CFileDialog dlg(
        TRUE, _T("*.bmp;*.jpg;*.jpeg"), NULL,
        OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
        _T("image files (*.bmp; *.jpg;*.jpeg) |*.bmp; *.jpg; *.jpeg | All Files (*.*) |*.*||"), NULL
        );                                        // 选项图片的约定
    dlg.m_ofn.lpstrTitle = _T("Open Image");    // 打开文件对话框的标题名
    if (dlg.DoModal() != IDOK)                    // 判断是否获得图片
        return;

    CString mPath = dlg.GetPathName();            // 获取图片路径

    TheImage = cvLoadImage(mPath, 1);    // 读取图片、缓存到一个局部变量 ipl 中
    // Mat TheImage = imread(mPath,1);
    // drawpic(TheImage, IDC_PICTURE);
    ShowMatImgToWnd(GetDlgItem(IDC_PICTURE), TheImage);
    UpdateWindow();
}

//单幅图像信息熵计算
double CCamCalibrationDlg::Entropy(Mat img)
{
    double temp[256] = { 0.0 };

    // 计算每个像素的累积值
    for (int m = 0; m<img.rows; m++)
    {// 有效访问行列的方式
        const uchar* t = img.ptr<uchar>(m);
        for (int n = 0; n<img.cols; n++)
        {
            int i = t[n];
            temp[i] = temp[i] + 1;
        }
    }

    // 计算每个像素的概率
    for (int i = 0; i<256; i++)
    {
        temp[i] = temp[i] / (img.rows*img.cols);
    }

    double result = 0;
    // 计算图像信息熵
    for (int i = 0; i<256; i++)
    {
        if (temp[i] == 0.0)
            result = result;
        else
            result = result - temp[i] * (log(temp[i]) / log(2.0));
    }

    return result;

}

// 两幅图像联合信息熵计算
double CCamCalibrationDlg::ComEntropy(Mat img1, Mat img2, double img1_entropy, double img2_entropy)
{
    double temp[256][256] = { 0.0 };

    // 计算联合图像像素的累积值
    for (int m1 = 0, m2 = 0; m1 < img1.rows, m2 < img2.rows; m1++, m2++)
    {    // 有效访问行列的方式
        const uchar* t1 = img1.ptr<uchar>(m1);
        const uchar* t2 = img2.ptr<uchar>(m2);
        for (int n1 = 0, n2 = 0; n1 < img1.cols, n2 < img2.cols; n1++, n2++)
        {
            int i = t1[n1], j = t2[n2];
            temp[i][j] = temp[i][j] + 1;
        }
    }

    // 计算每个联合像素的概率
    for (int i = 0; i < 256; i++)
    {
        for (int j = 0; j < 256; j++)

        {
            temp[i][j] = temp[i][j] / (img1.rows*img1.cols);
        }
    }

    double result = 0.0;
    //计算图像联合信息熵
    for (int i = 0; i < 256; i++)
    {
        for (int j = 0; j < 256; j++)

        {
            if (temp[i][j] == 0.0)
                result = result;
            else
                result = result - temp[i][j] * (log(temp[i][j]) / log(2.0));
        }
    }

    //得到两幅图像的互信息熵
    img1_entropy = Entropy(img1);
    img2_entropy = Entropy(img2);
    result = img1_entropy + img2_entropy - result;

    return result;

}

Point2f CCamCalibrationDlg::Refresh_MacthPoints(Point2f point1, Point2f point2)
{

    int IMGSIDE = 10; //截取正方形子图的边长的一半
    int ScanSide = 5; //搜索半径

    Mat dst1;   // 视频帧图像上截取子图
    Mat dst2;   // 全景图像上截取子图

    Point2f CLSPoint, CRXPoint;
    //截取视频帧图像子图
    CLSPoint.x = point1.x - IMGSIDE;
    CLSPoint.y = point1.y - IMGSIDE;
    CRXPoint.x = point1.x + IMGSIDE;
    CRXPoint.y = point1.y + IMGSIDE;
    Rect ROI0(CLSPoint, CRXPoint);
    CamImage(ROI0).copyTo(dst1);

    Point2f TLSPoint, TRXPoint;
    //截取全景图图像子图
    TLSPoint.x = point2.x - IMGSIDE;
    TLSPoint.y = point2.y - IMGSIDE;
    TRXPoint.x = point2.x + IMGSIDE;
    TRXPoint.y = point2.y + IMGSIDE;
    Rect ROI00(TLSPoint, TRXPoint);
    TheImage(ROI00).copyTo(dst2);

    //计算对应图像子块的互信息熵
    double OneImaEntropy1; //视频帧图像信息熵
    double OneImaEntropy2; //全景图信息熵
    double TwoImaEntropy; //初始互信息熵

    OneImaEntropy1 = Entropy(dst1);
    OneImaEntropy2 = Entropy(dst2);
    TwoImaEntropy = ComEntropy(dst1, dst2, OneImaEntropy1, OneImaEntropy2);

    Point2f NewPoints; // 更新的匹配点

    Point2f Points;
    Mat dst;

    double OneImaEntropy;
    double NewTwoEntropy;
    double MAX = TwoImaEntropy;

    for (int i = -ScanSide; i <= ScanSide; i++)
    {
        for (int j = -ScanSide; j <= ScanSide; j++)
        {
            NewPoints.x = point2.x + i;
            NewPoints.y = point2.y + j;

            Rect rect(NewPoints.x - IMGSIDE, NewPoints.y - IMGSIDE, 2 * IMGSIDE, 2 * IMGSIDE);
            TheImage(rect).copyTo(dst);

            OneImaEntropy = Entropy(dst);
            NewTwoEntropy = ComEntropy(dst, dst1, OneImaEntropy, OneImaEntropy1);

            if (NewTwoEntropy > MAX)   // 计算所有互信息熵,然后取最大值的坐标点
            {
                MAX = NewTwoEntropy;
                //Points = NewPoints;
                Points.x = point2.x + i;
                Points.y = point2.y + j;
            }

        }
    }

    return Points;
}

// 鼠标点击坐标转换为实际图像坐标
Point2f CCamCalibrationDlg::MousePointToImgPixel(Mat img, CRect rect, Point2f point)
{
    Point2f imgpix;
    imgpix.x = point.x / (rect.right - rect.left) * img.cols;
    imgpix.y = point.y / (rect.bottom - rect.top) * img.rows;

    return imgpix;
}

void CCamCalibrationDlg::OnBnClickedVideoPreview()
{

    switch (m_Radio)
    {
      case 1:
          capture = cvCaptureFromAVI("51_20150115161213.avi");

          break;
      case 2:
          capture = cvCaptureFromAVI("53_20150115161348.avi");

          break;
      case 3:
          capture = cvCaptureFromAVI("54_20150115161515.avi");

          break;
      case 4:
          capture = cvCaptureFromAVI("56_20150115161648.avi");

          break;
      case 5:
          capture = cvCaptureFromAVI("58_20150115161823.avi");

          break;
      case 6:
          capture = cvCaptureFromAVI("59_20150115161946.avi");

          break;
    default:
        break;
    }

    CamImage = cvQueryFrame(capture); //获取一帧图片
    //CamImage = imread("22.jpg");
    ShowMatImgToWnd(GetDlgItem(IDC_VIDEO), CamImage);

}

void CCamCalibrationDlg::OnBnClickedVideoPlay()
{
    // TODO:  在此添加控件通知处理程序代码
    //if (!capture)
    //{
    //  // capture = cvCaptureFromCAM(0);//调取摄像头
    //  capture = cvCaptureFromAVI("53_20150115161348.avi");//调取视频
    //}
    Mat m_Frame;
    // m_Frame = cvQueryFrame(capture);
    g_m_run = 1;
    while(g_m_run == 1)
    {
        m_Frame = cvQueryFrame(capture);
        ShowMatImgToWnd(GetDlgItem(IDC_VIDEO), m_Frame);
        char c = cvWaitKey(33);
    }

    // 设置计时器,每30ms触发一次事件
    // SetTimer(1, 1000 / 25, NULL);

}

void CCamCalibrationDlg::OnBnClickedVideoPause()
{
    // TODO:  在此添加控件通知处理程序代码
    g_m_run = 0;

}

//void CCamCalibrationDlg::OnTimer(UINT_PTR nIDEvent)
//{
//  // TODO:  在此添加消息处理程序代码和/或调用默认值
//  Mat m_Frame;
//  m_Frame = cvQueryFrame(capture);
//
//
//  if (g_m_run = 1)
//  {
//      ShowMatImgToWnd(GetDlgItem(IDC_VIDEO), m_Frame);
//  }
//
//  CDialogEx::OnTimer(nIDEvent);
//}

void CCamCalibrationDlg::OnBnClickedRadio1()
{
    // TODO:  在此添加控件通知处理程序代码
    m_Radio = 1;
}

void CCamCalibrationDlg::OnBnClickedRadio2()
{
    // TODO:  在此添加控件通知处理程序代码
    m_Radio = 2;
}

void CCamCalibrationDlg::OnBnClickedRadio3()
{
    // TODO:  在此添加控件通知处理程序代码
    m_Radio = 3;
}

void CCamCalibrationDlg::OnBnClickedRadio4()
{
    // TODO:  在此添加控件通知处理程序代码
    m_Radio = 4;
}

void CCamCalibrationDlg::OnBnClickedRadio5()
{
    // TODO:  在此添加控件通知处理程序代码
    m_Radio = 5;
}

void CCamCalibrationDlg::OnBnClickedRadio6()
{
    // TODO:  在此添加控件通知处理程序代码
    m_Radio = 6;
}

void CCamCalibrationDlg::OnBnClickedPictureChangeSize()
{
    // TODO:  在此添加控件通知处理程序代码
    Mat tmpImage = TheImage; //将全景图赋给临时图像
    Mat dstImage; //目标图像
    UpdateData(true); // 将控件数据传递给变量,更新显示
    //double    m_scale = 1.75;    //全景图缩放比率
    resize(tmpImage, dstImage, Size(tmpImage.cols * m_scale, tmpImage.rows * m_scale), CV_INTER_LINEAR);

    //pyrUp(tmpImage, dstImage, Size(tmpImage.cols * 0.5 , tmpImage.rows * 0.5));
    imshow("1", dstImage);
    TheImage = dstImage;
}

void CCamCalibrationDlg::OnBnClickedPicturePoints()
{
    // TODO:  在此添加控件通知处理程序代码
     m_Pointdownflag = 1;
}

void CCamCalibrationDlg::OnBnClickedVideoPoints()
{
    // TODO:  在此添加控件通知处理程序代码
    m_Pointdownflag = 2;
}

void CCamCalibrationDlg::OnBnClickedSavePoints()
{
    // TODO:  在此添加控件通知处理程序代码
    m_Pointdownflag = 3;
}

void CCamCalibrationDlg::OnBnClickedAdjustPoints()
{
    // TODO:  在此添加控件通知处理程序代码
    vector<Point2f> Newpoints;// 需要利用互信息子函数更新得到的匹配点集(要求四个) 

    vector<Point2f> Points1;// 视频帧图像匹配点集(要求四个)
    vector<Point2f> Points2;// 全景图像匹配点集,初始匹配点集(要求四个)

    for (int i = 0; i < m_points1.size(); i++)
    {

        Point2f CamImagePix = MousePointToImgPixel(CamImage, m_CamImageRect, m_points1[i]);
        Points1.push_back(CamImagePix);
    }

    for (int i = 0; i < m_points2.size(); i++)
    {

        Point2f TheImagePix = MousePointToImgPixel(TheImage, m_TheImageRect, m_points2[i]);
        Points2.push_back(TheImagePix);
    }

    for (int i = 0; i < Points2.size(); i++)
    {
        Point2f Newpoint = Refresh_MacthPoints(Points1[i], Points2[i]);//查找全景图上四个精确匹配点集
        Newpoints.push_back(Newpoint);
    }

    m_newpoints = Newpoints;

    //清空临时容器
     Newpoints.clear();
     Points1.clear();
     Points2.clear();

}

void CCamCalibrationDlg::OnBnClickedQuit()
{
    // TODO:  在此添加控件通知处理程序代码
    CDialogEx::OnCancel();
}

void CCamCalibrationDlg::OnBnClickedHomgtaphyFind()
{
    // TODO:  在此添加控件通知处理程序代码

    vector <Point2f> TheImgPix;
    vector <Point2f> CamImgPix;

    for (int i = 0; i < m_points1.size(); i++)
    {

        Point2f CamImagePix = MousePointToImgPixel(CamImage, m_CamImageRect, m_points1[i]);
        CamImgPix.push_back(CamImagePix);
    }

    //校准后匹配
    //for (int i = 0; i < m_newpoints.size(); i++)
    //{
    //  Point2f TheImagePix = MousePointToImgPixel(TheImage, m_TheImageRect, m_newpoints[i]);
    //  TheImgPix.push_back(TheImagePix);
    //}

     // TheImgPix = m_newpoints;

    //校准前匹配
    for (int i = 0; i < m_points2.size(); i++)
    {
        Point2f TheImagePix = MousePointToImgPixel(TheImage, m_TheImageRect, m_points2[i]);
        TheImgPix.push_back(TheImagePix);
    }

     FileStorage fs1(".\\H1.xml", FileStorage::WRITE);
     FileStorage fs2(".\\H2.xml", FileStorage::WRITE);
     FileStorage fs3(".\\H3.xml", FileStorage::WRITE);
     FileStorage fs4(".\\H4.xml", FileStorage::WRITE);
     FileStorage fs5(".\\H5.xml", FileStorage::WRITE);
     FileStorage fs6(".\\H6.xml", FileStorage::WRITE);

     switch (m_Radio)
     {
     case 1:
         H1 = getPerspectiveTransform(CamImgPix, TheImgPix);//src ,dst
         fs1 << "H1" << H1;
         fs1.release();
         break;
     case 2:
         H2 = getPerspectiveTransform(CamImgPix, TheImgPix);//src ,dst
         fs2 << "H2" << H2;
         fs2.release();
         break;
     case 3:
         H3 = getPerspectiveTransform(CamImgPix, TheImgPix);//src ,dst
         fs3 << "H3" << H3;
         fs3.release();
         break;
     case 4:
         H4 = getPerspectiveTransform(CamImgPix, TheImgPix);//src ,dst
         fs4 << "H4" << H4;
         fs4.release();
         break;
     case 5:
         H5 = getPerspectiveTransform(CamImgPix, TheImgPix);//src ,dst
         fs5 << "H5" << H5;
         fs5.release();
         break;
     case 6:
         H6 = getPerspectiveTransform(CamImgPix, TheImgPix);//src ,dst
         fs6 << "H6" << H6;
         fs6.release();
         break;
     default:
         break;
     }

     TheImgPix.clear();//计算完H后清空
     CamImgPix.clear();
}

void CCamCalibrationDlg::OnBnClickedCalibration()
{
    // TODO:  在此添加控件通知处理程序代码

    //清空容器里的坐标点
     m_newpoints.clear();
     m_points1.clear();
     m_points2.clear();

    Mat CamImage1;
    CamImage1 = cvQueryFrame(capture);
    Mat logoWarped;

    if (true)
    {
        CamImage1 = cvQueryFrame(capture);
        switch (m_Radio)
        {
        case 1:
            warpPerspective(CamImage1, logoWarped, H1, TheImage.size(), INTER_LINEAR, BORDER_CONSTANT);
            break;
        case 2:
            warpPerspective(CamImage1, logoWarped, H2, TheImage.size(), INTER_LINEAR, BORDER_CONSTANT);
            break;
        case 3:
            warpPerspective(CamImage1, logoWarped, H3, TheImage.size(), INTER_LINEAR, BORDER_CONSTANT);
            break;
        case 4:
            warpPerspective(CamImage1, logoWarped, H4, TheImage.size(), INTER_LINEAR, BORDER_CONSTANT);
            break;
        case 5:
            warpPerspective(CamImage1, logoWarped, H5, TheImage.size(), INTER_LINEAR, BORDER_CONSTANT);
            break;
        case 6:
            warpPerspective(CamImage1, logoWarped, H6, TheImage.size(), INTER_LINEAR, BORDER_CONSTANT);
            break;
        default:
            break;
        }

        Mat TheImage1;
        TheImage1 = showFinal(TheImage, logoWarped);
        TheImage = TheImage1;

        //ShowMatImgToWnd(GetDlgItem(IDC_VIDEO), m_Frame);
    }
    // 设置计时器,每30ms触发一次事件
    SetTimer(1, 1000 / 25, NULL);
}

Mat  CCamCalibrationDlg::showFinal(Mat src1, Mat src2)
{

    Mat gray, gray_inv, src1final, src2final;
    cvtColor(src2, gray, CV_BGR2GRAY);
    threshold(gray, gray, 0, 255, CV_THRESH_BINARY);
    //adaptiveThreshold(gray,gray,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,5,4);
    bitwise_not(gray, gray_inv);
    src1.copyTo(src1final, gray_inv);
    src2.copyTo(src2final, gray);
    Mat finalImage = src1final + src2final;
    // src1 = finalImage;
    ShowMatImgToWnd(GetDlgItem(IDC_PICTURE), finalImage);

    return finalImage;
}

void CCamCalibrationDlg::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO:  在此添加消息处理程序代码和/或调用默认值
        switch (m_Pointdownflag)
        {
        case 1:
            m_TheImage.GetWindowRect(m_TheImageRect);//获取显示全景图像所在矩形窗的坐标
            ScreenToClient(m_TheImageRect);         //转换为对话框上的坐标
            point.x -= m_TheImageRect.left;//point获取的是鼠标相对对话框客户区左上角的坐标,减去rect_ctr.left和
            point.y -= m_TheImageRect.top;//rect_ctr.top后,即为鼠标相对Picture控件左上角的坐标

            if (point.x>(m_TheImageRect.right - m_TheImageRect.left) || point.y>(m_TheImageRect.bottom - m_TheImageRect.top) || point.x<0 || point.y<0)
                ;
            else
            {
                m_pt.Format("x=%f,y=%f", float(point.x), float(point.y));
            }
            UpdateData(false); // 将数据传给控件显示,更新显示
            break;
        case 2:
            m_CamImage.GetWindowRect(m_CamImageRect);//获取显示视频帧图像所在矩形窗
            ScreenToClient(m_CamImageRect);         //转换为对话框上的坐标
            point.x -= m_CamImageRect.left;//point获取的是鼠标相对对话框客户区左上角的坐标,减去rect_ctr.left和
            point.y -= m_CamImageRect.top;//rect_ctr.top后,即为鼠标相对Picture控件左上角的坐标

            if (point.x>(m_CamImageRect.right - m_CamImageRect.left) || point.y>(m_CamImageRect.bottom - m_CamImageRect.top) || point.x < 0 || point.y < 0)
                ;
            else
            {
                m_pt.Format("x=%f,y=%f", float(point.x), float(point.y));
            }
            UpdateData(false); // 将数据传给控件显示,更新显示
            break;
        case 3:
            m_TheImage.GetWindowRect(m_TheImageRect);//获取显示全景图像所在矩形窗的坐标
            ScreenToClient(m_TheImageRect);         //转换为对话框上的坐标
            point.x -= m_TheImageRect.left;//point获取的是鼠标相对对话框客户区左上角的坐标,减去rect_ctr.left和
            point.y -= m_TheImageRect.top;//rect_ctr.top后,即为鼠标相对Picture控件左上角的坐标

            if (point.x>(m_TheImageRect.right - m_TheImageRect.left) || point.y>(m_TheImageRect.bottom - m_TheImageRect.top) || point.x<0 || point.y<0)
                ;
            else
            {
                m_pt.Format("x=%f,y=%f", float(point.x), float(point.y));
            }
            UpdateData(false); // 将数据传给控件显示,更新显示
            break;
        default:
            break;
        }

    CDialogEx::OnMouseMove(nFlags, point);
}

void CCamCalibrationDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO:  在此添加消息处理程序代码和/或调用默认值

    switch (m_Pointdownflag)
    {
    case 1:
        m_TheImage.GetWindowRect(m_TheImageRect);//获取显示全景图像所在矩形窗的坐标
        ScreenToClient(m_TheImageRect);         //转换为对话框上的坐标
        point.x -= m_TheImageRect.left;//point获取的是鼠标相对对话框客户区左上角的坐标,减去rect_ctr.left和
        point.y -= m_TheImageRect.top;//rect_ctr.top后,即为鼠标相对Picture控件左上角的坐标

        if (m_points2.size() <= 3)
        {
            m_points2.push_back(Point2f(float(point.x), float(point.y)));
        }
        else return;
        break;
    case 2:
        m_CamImage.GetWindowRect(m_CamImageRect);//获取显示视频帧图像所在矩形窗
        ScreenToClient(m_CamImageRect);         //转换为对话框上的坐标
        point.x -= m_CamImageRect.left;//point获取的是鼠标相对对话框客户区左上角的坐标,减去rect_ctr.left和
        point.y -= m_CamImageRect.top;//rect_ctr.top后,即为鼠标相对Picture控件左上角的坐标

        if (m_points1.size() <= 3)
        {
            m_points1.push_back(Point2f(float(point.x), float(point.y)));
        }
        else return;
        break;
    case 3:
        m_TheImage.GetWindowRect(m_TheImageRect);//获取显示全景图像所在矩形窗的坐标
        ScreenToClient(m_TheImageRect);         //转换为对话框上的坐标
        point.x -= m_TheImageRect.left;//point获取的是鼠标相对对话框客户区左上角的坐标,减去rect_ctr.left和
        point.y -= m_TheImageRect.top;//rect_ctr.top后,即为鼠标相对Picture控件左上角的坐标
        //Point2f imgpix;
        //imgpix.x = point.x / (m_TheImageRect.right - m_TheImageRect.left) * TheImage.cols;
        //imgpix.y = point.y / (m_TheImageRect.bottom - m_TheImageRect.top) * TheImage.rows;
        switch (m_Radio)
        {
        case 1:
            if (m_pointsh1.size() <= 3)
            {
                m_pointsh1.push_back(Point2f(float(point.x), float(point.y)));
            }
            else return;
            break;
        case 2:
            if (m_pointsh2.size() <= 3)
            {
                m_pointsh2.push_back(Point2f(float(point.x), float(point.y)));
            }
            else return;
            break;
        case 3:
            if (m_pointsh3.size() <= 3)
            {
                m_pointsh3.push_back(Point2f(float(point.x), float(point.y)));
            }
            else return;
            break;
        case 4:
            if (m_pointsh4.size() <= 3)
            {
                m_pointsh4.push_back(Point2f(float(point.x), float(point.y)));
            }
            else return;
            break;
        case 5:
            if (m_pointsh5.size() <= 3)
            {
                m_pointsh5.push_back(Point2f(float(point.x), float(point.y)));
            }
            else return;
            break;
        case 6:
            if (m_pointsh6.size() <= 3)
            {
                m_pointsh6.push_back(Point2f(float(point.x), float(point.y)));
            }
            else return;
            break;
        /*default:
            break;*/
        }
    //default:
    //  break;
    }

    CDialogEx::OnLButtonDown(nFlags, point);
}

void CCamCalibrationDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
    // TODO:  在此添加消息处理程序代码和/或调用默认值
    if (!bFullScreen)
    {
        bFullScreen = true;
        //获取系统屏幕宽高
        int g_iCurScreenWidth = GetSystemMetrics(SM_CXSCREEN);
        int g_iCurScreenHeight = GetSystemMetrics(SM_CYSCREEN);

        //用m_struOldWndpl得到当前窗口的显示状态和窗体位置,以供退出全屏后使用
        GetWindowPlacement(&m_struOldWndpl);
        GetDlgItem(IDC_PICTURE)->GetWindowPlacement(&m_struOldWndpPic);

        //计算出窗口全屏显示客户端所应该设置的窗口大小,主要为了将不需要显示的窗体边框等部分排除在屏幕外
        CRect rectWholeDlg;
        CRect rectClient;
        GetWindowRect(&rectWholeDlg);//得到当前窗体的总的相对于屏幕的坐标
        RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, &rectClient);//得到客户区窗口坐标
        ClientToScreen(&rectClient);//将客户区相对窗体的坐标转为相对屏幕坐标
        //GetDlgItem(IDC_STATIC_PICSHOW)->GetWindowRect(rectClient);//得到PICTURE控件坐标

        rectFullScreen.left = rectWholeDlg.left - rectClient.left;
        rectFullScreen.top = rectWholeDlg.top - rectClient.top;
        rectFullScreen.right = rectWholeDlg.right + g_iCurScreenWidth - rectClient.right;
        rectFullScreen.bottom = rectWholeDlg.bottom + g_iCurScreenHeight - rectClient.bottom;

        //设置窗口对象参数,为全屏做好准备并进入全屏状态
        WINDOWPLACEMENT struWndpl;
        struWndpl.length = sizeof(WINDOWPLACEMENT);
        struWndpl.flags = 0;
        struWndpl.showCmd = SW_SHOWNORMAL;
        struWndpl.rcNormalPosition = rectFullScreen;
        SetWindowPlacement(&struWndpl);//该函数设置指定窗口的显示状态和显示大小位置等,是我们该程序最为重要的函数

        //将PICTURE控件的坐标设为全屏大小
        GetDlgItem(IDC_PICTURE)->MoveWindow(CRect(0, 0, g_iCurScreenWidth, g_iCurScreenHeight));

    }
    else
    {
        GetDlgItem(IDC_PICTURE)->SetWindowPlacement(&m_struOldWndpPic);
        SetWindowPlacement(&m_struOldWndpl);
        bFullScreen = false;
    }
    CDialogEx::OnLButtonDblClk(nFlags, point);
}

void CCamCalibrationDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
    // TODO:  在此添加消息处理程序代码和/或调用默认值
    if (bFullScreen)
    {
        lpMMI->ptMaxSize.x = rectFullScreen.Width();
        lpMMI->ptMaxSize.y = rectFullScreen.Height();
        lpMMI->ptMaxPosition.x = rectFullScreen.left;
        lpMMI->ptMaxPosition.y = rectFullScreen.top;
        lpMMI->ptMaxTrackSize.x = rectFullScreen.Width();
        lpMMI->ptMaxTrackSize.y = rectFullScreen.Height();
    }
    CDialogEx::OnGetMinMaxInfo(lpMMI);
}

void CCamCalibrationDlg::drawpic(IplImage* img, unsigned int id)//CShowPictureInFullScreenDlg 为对话框类名
{
    BYTE *g_pBits;
    HDC g_hMemDC;
    HBITMAP g_hBmp, g_hOldBmp;
    CDC *pDC;
    CStatic *pic;
    int width, height;
    CRect rect;

    pDC = GetDlgItem(id)->GetDC();
    pic = (CStatic*)GetDlgItem(id);
    pic->GetClientRect(&rect);
    width = rect.Width();
    height = rect.Height();

    g_hMemDC = ::CreateCompatibleDC(pDC->m_hDC);//创建兼容DC

    BYTE bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
    memset(bmibuf, 0, sizeof(bmibuf));
    BITMAPINFO *pbmi = (BITMAPINFO*)bmibuf;

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = img->width;
    pbmi->bmiHeader.biHeight = img->height;
    pbmi->bmiHeader.biPlanes = 1;
    pbmi->bmiHeader.biBitCount = 24;
    pbmi->bmiHeader.biCompression = BI_RGB;

    g_hBmp = ::CreateDIBSection(g_hMemDC, pbmi, DIB_RGB_COLORS, (void**)&g_pBits, 0, 0);//创建应用程序可以直接写入的、与设备无关的位图(DIB)
    g_hOldBmp = (HBITMAP)::SelectObject(g_hMemDC, g_hBmp);//复原兼容DC数据
    BitBlt(g_hMemDC, 0, 0, width, height, pDC->m_hDC, 0, 0, SRCCOPY);

    //修改图像内容:g_pBits
    int l_width = WIDTHBYTES(img->width* pbmi->bmiHeader.biBitCount);
    for (int row = 0; row < img->height; row++)
        memcpy(&g_pBits[row*l_width], &img->imageData[(img->height - row - 1)*l_width], l_width);

    TransparentBlt(pDC->m_hDC, 0, 0, width, height, g_hMemDC, 0, 0, img->width, img->height, RGB(0, 0, 0));
    SelectObject(g_hMemDC, g_hOldBmp);

    //释放内存资源
    ReleaseDC(pDC);
    DeleteDC(g_hMemDC);
    DeleteObject(pic);
    DeleteObject(g_hBmp);
    DeleteObject(g_hOldBmp);
}
#ifndef CVVIMAGE_CLASS_DEF
#define CVVIMAGE_CLASS_DEF  

#ifndef RC_OPENCV_2_1_0  

#include <opencv/cv.h>
#include <opencv/highgui.h>  

/* CvvImage class definition */
class  CvvImage
{
public:
    CvvImage();
    virtual ~CvvImage();

    /* Create image (BGR or grayscale) */
    virtual bool  Create(int width, int height, int bits_per_pixel, int image_origin = 0);

    /* Load image from specified file */
    virtual bool  Load(const char* filename, int desired_color = 1);

    /* Load rectangle from the file */
    virtual bool  LoadRect(const char* filename,
        int desired_color, CvRect r);

#if defined WIN32 || defined _WIN32
    virtual bool  LoadRect(const char* filename,
        int desired_color, RECT r)
    {
        return LoadRect(filename, desired_color,
            cvRect(r.left, r.top, r.right - r.left, r.bottom - r.top));
    }
#endif  

    /* Save entire image to specified file. */
    virtual bool  Save(const char* filename);

    /* Get copy of input image ROI */
    virtual void  CopyOf(CvvImage& image, int desired_color = -1);
    virtual void  CopyOf(IplImage* img, int desired_color = -1);

    IplImage* GetImage() { return m_img; };
    virtual void  Destroy(void);

    /* width and height of ROI */
    int Width() { return !m_img ? 0 : !m_img->roi ? m_img->width : m_img->roi->width; };
    int Height() { return !m_img ? 0 : !m_img->roi ? m_img->height : m_img->roi->height; };
    int Bpp() { return m_img ? (m_img->depth & 255)*m_img->nChannels : 0; };

    virtual void  Fill(int color);

    /* draw to highgui window */
    virtual void  Show(const char* window);

#if defined WIN32 || defined _WIN32
    /* draw part of image to the specified DC */
    virtual void  Show(HDC dc, int x, int y, int width, int height,
        int from_x = 0, int from_y = 0);
    /* draw the current image ROI to the specified rectangle of the destination DC */
    virtual void  DrawToHDC(HDC hDCDst, RECT* pDstRect);
#endif  

protected:

    IplImage*  m_img;
};

typedef CvvImage CImage;

#endif  

#endif  
#include "StdAfx.h"
#include "CvvImage.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CV_INLINE RECT NormalizeRect(RECT r);
CV_INLINE RECT NormalizeRect(RECT r)
{
    int t;
    if (r.left > r.right)
    {
        t = r.left;
        r.left = r.right;
        r.right = t;
    }
    if (r.top > r.bottom)
    {
        t = r.top;
        r.top = r.bottom;
        r.bottom = t;
    }

    return r;
}
CV_INLINE CvRect RectToCvRect(RECT sr);
CV_INLINE CvRect RectToCvRect(RECT sr)
{
    sr = NormalizeRect(sr);
    return cvRect(sr.left, sr.top, sr.right - sr.left, sr.bottom - sr.top);
}
CV_INLINE RECT CvRectToRect(CvRect sr);
CV_INLINE RECT CvRectToRect(CvRect sr)
{
    RECT dr;
    dr.left = sr.x;
    dr.top = sr.y;
    dr.right = sr.x + sr.width;
    dr.bottom = sr.y + sr.height;

    return dr;
}
CV_INLINE IplROI RectToROI(RECT r);
CV_INLINE IplROI RectToROI(RECT r)
{
    IplROI roi;
    r = NormalizeRect(r);
    roi.xOffset = r.left;
    roi.yOffset = r.top;
    roi.width = r.right - r.left;
    roi.height = r.bottom - r.top;
    roi.coi = 0;

    return roi;
}
void  FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin)
{
    assert(bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));

    BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);

    memset(bmih, 0, sizeof(*bmih));
    bmih->biSize = sizeof(BITMAPINFOHEADER);
    bmih->biWidth = width;
    bmih->biHeight = origin ? abs(height) : -abs(height);
    bmih->biPlanes = 1;
    bmih->biBitCount = (unsigned short)bpp;
    bmih->biCompression = BI_RGB;
    if (bpp == 8)
    {
        RGBQUAD* palette = bmi->bmiColors;
        int i;
        for (i = 0; i < 256; i++)
        {
            palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
            palette[i].rgbReserved = 0;
        }
    }
}
CvvImage::CvvImage()
{
    m_img = 0;
}
void CvvImage::Destroy()
{
    cvReleaseImage(&m_img);
}
CvvImage::~CvvImage()
{
    Destroy();
}
bool  CvvImage::Create(int w, int h, int bpp, int origin)
{
    const unsigned max_img_size = 10000;

    if ((bpp != 8 && bpp != 24 && bpp != 32) ||
        (unsigned)w >= max_img_size || (unsigned)h >= max_img_size ||
        (origin != IPL_ORIGIN_TL && origin != IPL_ORIGIN_BL))
    {
        assert(0); // most probably, it is a programming error
        return false;
    }
    if (!m_img || Bpp() != bpp || m_img->width != w || m_img->height != h)
    {
        if (m_img && m_img->nSize == sizeof(IplImage))
            Destroy();
        /* prepare IPL header */
        m_img = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, bpp / 8);
    }
    if (m_img)
        m_img->origin = origin == 0 ? IPL_ORIGIN_TL : IPL_ORIGIN_BL;
    return m_img != 0;
}
void  CvvImage::CopyOf(CvvImage& image, int desired_color)
{
    IplImage* img = image.GetImage();
    if (img)
    {
        CopyOf(img, desired_color);
    }
}
#define HG_IS_IMAGE(img)                                                  \
   ((img) != 0 && ((const IplImage*)(img))->nSize == sizeof(IplImage) &&    ((IplImage*)img)->imageData != 0)
void  CvvImage::CopyOf(IplImage* img, int desired_color)
{
    if (HG_IS_IMAGE(img))
    {
        int color = desired_color;
        CvSize size = cvGetSize(img);
        if (color < 0)
            color = img->nChannels > 1;
        if (Create(size.width, size.height,
            (!color ? 1 : img->nChannels > 1 ? img->nChannels : 3) * 8,
            img->origin))
        {
            cvConvertImage(img, m_img, 0);
        }
    }
}
bool  CvvImage::Load(const char* filename, int desired_color)
{
    IplImage* img = cvLoadImage(filename, desired_color);
    if (!img)
        return false;

    CopyOf(img, desired_color);
    cvReleaseImage(&img);

    return true;
}
bool  CvvImage::LoadRect(const char* filename,
    int desired_color, CvRect r)
{
    if (r.width < 0 || r.height < 0) return false;

    IplImage* img = cvLoadImage(filename, desired_color);
    if (!img)
        return false;
    if (r.width == 0 || r.height == 0)
    {
        r.width = img->width;
        r.height = img->height;
        r.x = r.y = 0;
    }
    if (r.x > img->width || r.y > img->height ||
        r.x + r.width < 0 || r.y + r.height < 0)
    {
        cvReleaseImage(&img);
        return false;
    }
    /* truncate r to source image */
    if (r.x < 0)
    {
        r.width += r.x;
        r.x = 0;
    }
    if (r.y < 0)
    {
        r.height += r.y;
        r.y = 0;
    }
    if (r.x + r.width > img->width)
        r.width = img->width - r.x;

    if (r.y + r.height > img->height)
        r.height = img->height - r.y;
    cvSetImageROI(img, r);
    CopyOf(img, desired_color);
    cvReleaseImage(&img);
    return true;
}
bool  CvvImage::Save(const char* filename)
{
    if (!m_img)
        return false;
    cvSaveImage(filename, m_img);
    return true;
}
void  CvvImage::Show(const char* window)
{
    if (m_img)
        cvShowImage(window, m_img);
}
void  CvvImage::Show(HDC dc, int x, int y, int w, int h, int from_x, int from_y)
{
    if (m_img && m_img->depth == IPL_DEPTH_8U)
    {
        uchar buffer[sizeof(BITMAPINFOHEADER) + 1024];
        BITMAPINFO* bmi = (BITMAPINFO*)buffer;
        int bmp_w = m_img->width, bmp_h = m_img->height;
        FillBitmapInfo(bmi, bmp_w, bmp_h, Bpp(), m_img->origin);
        from_x = MIN(MAX(from_x, 0), bmp_w - 1);
        from_y = MIN(MAX(from_y, 0), bmp_h - 1);
        int sw = MAX(MIN(bmp_w - from_x, w), 0);
        int sh = MAX(MIN(bmp_h - from_y, h), 0);
        SetDIBitsToDevice(
            dc, x, y, sw, sh, from_x, from_y, from_y, sh,
            m_img->imageData + from_y*m_img->widthStep,
            bmi, DIB_RGB_COLORS);
    }
}
void  CvvImage::DrawToHDC(HDC hDCDst, RECT* pDstRect)
{
    if (pDstRect && m_img && m_img->depth == IPL_DEPTH_8U && m_img->imageData)
    {
        uchar buffer[sizeof(BITMAPINFOHEADER) + 1024];
        BITMAPINFO* bmi = (BITMAPINFO*)buffer;
        int bmp_w = m_img->width, bmp_h = m_img->height;
        CvRect roi = cvGetImageROI(m_img);
        CvRect dst = RectToCvRect(*pDstRect);
        if (roi.width == dst.width && roi.height == dst.height)
        {
            Show(hDCDst, dst.x, dst.y, dst.width, dst.height, roi.x, roi.y);
            return;
        }
        if (roi.width > dst.width)
        {
            SetStretchBltMode(
                hDCDst,           // handle to device context
                HALFTONE);
        }
        else
        {
            SetStretchBltMode(
                hDCDst,           // handle to device context
                COLORONCOLOR);
        }
        FillBitmapInfo(bmi, bmp_w, bmp_h, Bpp(), m_img->origin);
        ::StretchDIBits(
            hDCDst,
            dst.x, dst.y, dst.width, dst.height,
            roi.x, roi.y, roi.width, roi.height,
            m_img->imageData, bmi, DIB_RGB_COLORS, SRCCOPY);
    }
}
void  CvvImage::Fill(int color)
{
    cvSet(m_img, cvScalar(color & 255, (color >> 8) & 255, (color >> 16) & 255, (color >> 24) & 255));
}
时间: 2024-10-01 04:53:29

基于opencv的MFC多摄像机视场标定软件的相关文章

基于Opencv和Mfc的图像处理增强库GOCVHelper(索引)

GOCVHelper(GreenOpen Computer Version Helper )是我在这几年编写图像处理程序的过程中积累下来的函数库.主要是对Opencv的适当扩展和在实现Mfc程序时候的功能增强. 这里将算法库开放源代码,并且编写一系列blog对函数实现进行说明.目的是在于“取之于互联网,用之于互联网”.并且也希望该库能够继续发展下去. 由于算法库基于Opencv和Mfc进行编写,所以要求阅读使用者具备一定基础. 最终提交的是GOCVHelper.h 和GOCVHelper版本号.

基于opencv和mfc的摄像头采集代码(GOMFCTemplate2)

基于opencv和mfc的摄像头采集框架(GOMFCTemplate2) 编写带界面的图像处理程序,选择opencv+mfc是一种很好的选择:在读取摄像头数据方面,网上的方法很多,其中shiqiyu的camerads的方法是较好的. 基于现有资料,通过在实际项目中的积累,我总结出来一套结合opencv和mfc的摄像头采集框架.具有以下特点: 1.基于directshow,兼容性好,速度快.到目前为止,无论是工业相机还是普通相机,没发现不兼容的: 2.摄像头部分通过线程读取,保证界面的运行流畅:

基于OpenCV单目相机的快速标定--源码、工程、实现过程

相机的标定是所有人走进视觉世界需要做的第一件事,辣么多的视觉标定原理解释你可以随便在网上找到,这里只讲到底如何去实现,也算是给刚入门的朋友做个简单的分享. 1.单目相机标定的工程源码 首先请到同性交友网站Github上下载工程源码(https://github.com/Zhanggx0102/Camera_Calibration),注意以下几点: 1).这是一个MS Visual Studio 2010的工程源码(版本是201x都可以). 2).在编译运行之前请先在VS中配置好OpenCV(网上

基于 OpenCV 的人脸识别

基于 OpenCV 的人脸识别 一点背景知识 OpenCV 是一个开源的计算机视觉和机器学习库.它包含成千上万优化过的算法,为各种计算机视觉应用提供了一个通用工具包.根据这个项目的关于页面,OpenCV 已被广泛运用在各种项目上,从谷歌街景的图片拼接,到交互艺术展览的技术实现中,都有 OpenCV 的身影. OpenCV 起始于 1999 年 Intel 的一个内部研究项目.从那时起,它的开发就一直很活跃.进化到现在,它已支持如 OpenCL 和 OpenGL 的多种现代技术,也支持如 iOS

基于OpenCV的图片卡通化处理

学习OpenCV已有一段时间,除了研究各种算法的内容,在空闲之余,根据书本及资料的引导,尝试结合图像处理算法和日常生活联系起来,首先在台式机上(带摄像头)完成一系列视频流处理功能,开发平台为Qt5.3.2+OpenCV2.4.9. 本次试验实现的功能主要有: 调用摄像头捕获视频流: 将帧图像转换为素描效果图片: 将帧图像卡通化处理: 简单地生成"怪物"形象: 人脸肤色变换. 本节所有的算法均由类cartoon中的函数cartoonTransform()来实现: // Frame:输入每

基于OpenCV做“三维重建”(1)--找到并绘制棋盘

<OpenCV计算机视觉编程攻略(第3版)>这套书已经出到第3版了,如果你非要我说这本书有多好,我说不出来:只是很多我第一手的例子都是来源于这本书的-相比较OpenCV官方提供的代码,这本书的例子提供了更好的帮助.所以说这里我还将继续这个工作,将来我自己出书的时候这种模式也是可选的.      这里我要做的是第11章,关于3维重建的相关内容.[读书,做例子,多么轻松的学生岁月--] 例子11.2.1 获得图片的角点并且绘制出来. // GOCVHelper.cpp : 定义控制台应用程序的入口

(转载)用vs2010开发基于VC++的MFC 串口通信一*****两台电脑同一个串口号之间的通信

此文章以visual C++数据採集与串口通信測控应用实战为參考教程 此文章适合VC++串口通信入门 一.页面布局及加入控件 1, 安装好vs2010如图 2, 新建一个基于VC++的MFC项目comm 注意:点击ok,然后next,这时候要将application type改成dialog base.接着next到最后一个对话框是将generated dasses改成CcommDlg,然后finish 4, 将新生成的项目的对话框默认dialog edit删去,如图 5,在对话框中加入两个st

基于opencv网络摄像头在ubuntu下的视频获取

 基于opencv网络摄像头在ubuntu下的视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译运行步骤 安装编译opencv-2.3  参考http://blog.csdn.net/xiabodan/article/details/23547847 3  测试代码 编译 g++ cameraCaptrue.cpp -o test `pkg-config --libs --cflags opencv` cameraCaptrue.cpp

Csharp调用基于Opencv编写的类库文件

现在将Csharp调用基于Opencv编写的类库文件(Dll)的方法定下来,我取名叫做GreenOpenCsharpWarper,简称GOCW. 一.CLR编写的DLL部分 1.按照正常方法引入Opencv; 2.提供接口函数,进行图像处理(这里只是实现了cvtColor,实际过程中可以用自己编写的复杂函数) String^  Class1::Method(cli::array<unsigned char>^ pCBuf1){     pin_ptr<System::Byte> p