一、项目需求
确定网络摄像机的监控视场在全景地图上的精确位置,并采用简单而高效的方法将其所在视场标定并投影到全景地图上,项目要求能够将多路网络摄像机的视场标定在全景地图上,并实现这样的功能:当调取当前摄像机视频播放时,其他摄像机处于暂停状态。
二、项目分析
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);
//绘图到 MFC 的 Picture Control 控件相关函数
//参数一为 OpenCV 的图像数据结构类,参数二为 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