一、图片旋转
- 建立图片控件
- 改变图片控件ID
- 建立四个按钮
- 改变四个控件ID
从上到下依次为:
IDC_LEFTTURN90DEGREES
IDC_RIGHTTURN90DEGREES
IDC_FLIPHORIZONTAL
IDC_FLIPVERTICALLY
- 建立三个私有的坐标,存左上角坐标,宽,高
private:
// 左上角坐标,宽,高
CPoint leftTop;
int imgControlWidth;
int imgControlHeight;
构造函数中初始化为(0,0),0,0
CCameraLinkTestDlg::CCameraLinkTestDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_CAMERALINKTEST_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
fg = NULL;
//图像宽和高
width = 640;
height = 512;
leftTop = (0, 0);
imgControlWidth = 0;
imgControlHeight = 0;
}
- 在:OnInitDialog中获取图片控件的坐标
CRect rect;
GetDlgItem(IDC_SHOWOPIMG)->GetClientRect(&rect);
leftTop.x = rect.left;
leftTop.y = rect.top;
imgControlWidth = rect.Width();
imgControlHeight = rect.Height();
- 为4个按钮添加点击响应函数
void CCameraLinkTestDlg::OnBnClickedLeftturn90degrees()
{
// TODO: 在此添加控件通知处理程序代码
//CStatic* pStatic = (CStatic*)GetDlgItem(IDC_SHOWOPIMG);
//pStatic->GetDC()->FillSolidRect(leftTop.x,leftTop.y,imgControlWidth,imgControlHeight, RGB(215, 220, 243));
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(FALSE);
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(TRUE);
if (imgOf8bit.empty())
{
GetDlgItem(IDC_PRINTMESSAGE)->SetWindowTextW(_T("请先读入图片"));
MessageBox(_T("请先读入图片"));
}
Mat img;
transpose(imgOf8bit, img);
flip(img, img, 0);
ShowMatImg(img, IDC_SHOWOPIMG, CPoint(int((imgControlWidth - img.cols) / 2) + leftTop.x, leftTop.y), leftTop);
}
void CCameraLinkTestDlg::OnBnClickedRightturn90degrees()
{
// TODO: 在此添加控件通知处理程序代码
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(FALSE);
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(TRUE);
Mat img;
if (imgOf8bit.empty())
{
GetDlgItem(IDC_PRINTMESSAGE)->SetWindowTextW(_T("请先读入图片"));
MessageBox(_T("请先读入图片"));
}
// 矩阵转置
transpose(imgOf8bit,img);
//0: 沿X轴翻转; >0: 沿Y轴翻转; <0: 沿X轴和Y轴翻转
flip(img,img , 1);// 翻转模式,flipCode == 0垂直翻转(沿X轴翻转),flipCode>0水平翻转(沿Y轴翻转),flipCode<0水平垂直翻转(先沿X轴翻转,再沿Y轴翻转,等价于旋转180°)
ShowMatImg(img, IDC_SHOWOPIMG, CPoint(int((imgControlWidth - img.cols) / 2) + leftTop.x,leftTop.y), leftTop);
}
void CCameraLinkTestDlg::OnBnClickedFliphorizontal()
{
// TODO: 在此添加控件通知处理程序代码
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(FALSE);
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(TRUE);
Mat img;
if (imgOf8bit.empty())
{
GetDlgItem(IDC_PRINTMESSAGE)->SetWindowTextW(_T("请先读入图片"));
MessageBox(_T("请先读入图片"));
}
flip(imgOf8bit, img, 1);
ShowMatImg(img, IDC_SHOWOPIMG, CPoint(int((imgControlWidth - img.cols) / 2) + leftTop.x, int((imgControlHeight - img.rows) / 2) + leftTop.y), leftTop);
}
void CCameraLinkTestDlg::OnBnClickedFlipvertically()
{
// TODO: 在此添加控件通知处理程序代码
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(FALSE);
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(TRUE);
Mat img;
if (imgOf8bit.empty())
{
GetDlgItem(IDC_PRINTMESSAGE)->SetWindowTextW(_T("请先读入图片"));
MessageBox(_T("请先读入图片"));
}
flip(imgOf8bit, img, 0);
ShowMatImg(img, IDC_SHOWOPIMG, CPoint(int((imgControlWidth - img.cols) / 2) + leftTop.x, int((imgControlHeight - img.rows) / 2) + leftTop.y), leftTop);
}
二、MFC 控件PictureControl 清除显示
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(FALSE);
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(TRUE);
三、伪彩
-
添加group box
改caption -
添加一个按钮
修改ID:IDC_PSEUDO_COLOR
-
添加命令响应函数
//伪彩
void CCameraLinkTestDlg::OnBnClickedPseudoColor()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(FALSE);
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(TRUE);
Mat img;
if (imgOf8bit.empty())
{
GetDlgItem(IDC_PRINTMESSAGE)->SetWindowTextW(_T("请先读入图片"));
MessageBox(_T("请先读入图片"));
return;
}
applyColorMap(imgOf8bit, img, COLORMAP_JET);
ShowMatImg(img, IDC_SHOWOPIMG, CPoint(int((imgControlWidth - img.cols) / 2) + leftTop.x, int((imgControlHeight - img.rows) / 2) + leftTop.y), leftTop);
}
四、直方图
-
添加滑块控件、2个按钮、一个编辑框
改ID:
- 滑块控件:IDC_HIST
- 编辑框:IDC_HISTSIZE
- 按钮:IDC_PRE和IDC_NEXT
2. 添加一个CSliderCtrl类的对象,类别为控件类型
private:
// 滑块控件对象
CSliderCtrl m_sliderCtrl;
void CCameraLinkTestDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_HIST, m_sliderCtrl);
}
- 为编辑框关联一个值类型的变量,变量名为m_histSize.
并初始化为50.
CCameraLinkTestDlg::CCameraLinkTestDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_CAMERALINKTEST_DIALOG, pParent)
, m_histSize(50)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
fg = NULL;
//图像宽和高
width = 640;
height = 512;
leftTop = (0, 0);
imgControlWidth = 0;
imgControlHeight = 0;
}
- 添加一个画直方图的成员函数
//画直方图
void CCameraLinkTestDlg::DrawHistImg()
{
// TODO: 在此处添加实现代码.
//先清空图像控件内的值
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(FALSE);
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(TRUE);
//判断图片是否为空,为空不能进行直方图显示
if (imgOf8bit.empty())
{
MessageBox(_T("请先捕获图片!"));
return;
}
//判断直方图的histSize是否为0,即像素分组数,为0则不能进行直方图显示
if (m_histSize == 0)
{
MessageBox(TEXT("请输入1-256之间的正整数!"));
return;
}
//直方图统计结果
Mat hist;
//统计图片的个数
int nimages = 1;
//需要统计的直方图维度
int dims = 1;
//每一维数值的取值范围ranges
float hranges[2] = { 0,255 };
const float* ranges[1] = { hranges };
//通道数量
int channels[1] = { 0 };
//计算图像的直方图,即计算出每一取值范围内的像素值个数
calcHist(&imgOf8bit, nimages, channels, cv::Mat(), hist, dims, &m_histSize, ranges);
//寻找最大值及其位置
double maxVal = 0;
//cv::Point maxLoc;
minMaxLoc(hist, NULL, &maxVal, NULL, NULL);
//直方图展示图,20和60用于显示刻度值的空间
Mat histImg(300+20,256*2+60, CV_8UC3, Scalar(255,255,255));
//m_histSize: 条的个数,则 bin_w 为每条的宽度
double bin_w = (double)(histImg.cols-60) / m_histSize;
// maxVal: 最高条的像素个数,则 bin_u 为单个像素的高度
double bin_u = (double)(histImg.rows-20) / maxVal;
//坐标系从左上角开始的,左上角为(0.0): 向左为+x方向,向下为+y方向
//所以纵坐标应该为:(histimg总高度-20)-某个范围内直方图统计点数 * 单个像素的高度
// 横坐标应该为:(histimg总宽度-60)-histSize * 每条的宽度
//画直方图
for (int i = 0; i < m_histSize; i++)
{
Point p0 = cv::Point(i * bin_w+60, histImg.rows-20);
float binV = hist.at<float>(i,0);
int binValue = binV;
Point p1 = Point((i + 1) * bin_w+60, histImg.rows-20- binValue * bin_u);
rectangle(histImg, p0, p1, Scalar(0, 0, 0), 2, 8, 0);
}
//曲线形式的直方图
for (int i = 0; i < m_histSize-1; i++)
{
float binV = hist.at<float>(i, 0); // 注意hist中是float类型
int binValue = binV;
float binV1 = hist.at<float>(i + 1, 0); // 注意hist中是float类型
int binValue1 = binV1;
int p0X = bin_w * i + int(bin_w / 2)+60;
int p0Y = histImg.rows - binValue * bin_u-20;
int p1X = bin_w * (i + 1) + int(bin_w / 2)+60;
int p1Y = histImg.rows - binValue1 * bin_u-20;
cv::line(histImg,Point(p0X, p0Y),Point(p1X, p1Y),
Scalar(255, 0, 0), 2, 8, 0);//bin_w/2是为了保证折现位于直方图每条的中间位置
}
//画纵坐标刻度(像素个数)
//存放坐标刻度
char string[10];
int kedu = 0;
for (int i = 1; kedu < maxVal; i++)
{
kedu = i * maxVal / 10;
_itoa(kedu, string, 10);//把一个整数转换为字符串
//在图像中显示文本字符串
//在图像中显示文本字符串
cv::putText(histImg, string, Point(0, histImg.rows - kedu * bin_u-20),
cv::FONT_HERSHEY_SIMPLEX, 0.5,Scalar(0, 0, 0), 1);
cv::line(histImg, Point(60, histImg.rows - kedu * bin_u-20),
Point(histImg.cols - 1, histImg.rows - kedu * bin_u-20),
Scalar(0, 0, 255));
}
//画横坐标刻度(像素灰度值)
kedu = 0;
for (int i = 1; kedu < 256; i++)
{
kedu = i * 20;
sprintf(string, "%d", kedu);//把一个整数转换为字符串
//在图像中显示文本字符串
putText(histImg, string, cv::Point(kedu * (histImg.cols / 256)+60, histImg.rows-3), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0), 2);
}
//显示图像
ShowMatImg(histImg, IDC_SHOWOPIMG, CPoint(int((imgControlWidth - histImg.cols) / 2) + leftTop.x, int((imgControlHeight - histImg.rows) / 2) + leftTop.y), leftTop);
}
- 在对话框初始化的代码OnInitDialog后设置滑块的属性。
//设置滑块
//用于查询和设置滑动条的取值范围,默认为0~100
m_sliderCtrl.SetRange(1, 256);
//用于设置滑动条刻度的频度。默认为一个单位一个函数
//m_sliderCtrl.SetTicFreq(10);
m_sliderCtrl.SetPos(50);
- 响应滑块的响应函数
void CCameraLinkTestDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//获得滑块的当前位置
UpdateData(TRUE);
m_histSize = m_sliderCtrl.GetPos();
DrawHistImg();
UpdateData(FALSE);
CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}
- 添加编辑框更改的响应函数
//编辑框输入信息就会触发此函数
void CCameraLinkTestDlg::OnEnChangeHistsize()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialogEx::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if (m_histSize>0&&m_histSize<=256)
{
m_sliderCtrl.SetPos(m_histSize);
DrawHistImg();
}
else
{
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(FALSE);
GetDlgItem(IDC_SHOWOPIMG)->ShowWindow(TRUE);
MessageBox(TEXT("请输入1-256之间的正整数!"));
}
UpdateData(FALSE);
}
- 为两个按钮添加点击响应函数
//点击 m_histSize-1
void CCameraLinkTestDlg::OnBnClickedPre()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if (m_histSize==1)
{
MessageBox(TEXT("不能输入小于1的数据!"));
return;
}
m_histSize -= 1;
m_sliderCtrl.SetPos(m_sliderCtrl.GetPos() - 1);
DrawHistImg();
UpdateData(FALSE);
}
// 点击 m_histSize + 1
void CCameraLinkTestDlg::OnBnClickedNext()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if (m_histSize == 256)
{
MessageBox(TEXT("不能输入大于256的数据!"));
return;
}
m_histSize += 1;
m_sliderCtrl.SetPos(m_sliderCtrl.GetPos() + 1);
DrawHistImg();
UpdateData(FALSE);
}
五、为按钮添加背景图标
-
将使用的icon图片添加到本项目的res文件夹中
-
导入icon资源视图中
-
将CButtonST工具类放入自己的项目中
这个工具类我上传过资源
-
导入工具类到项目中
-
为每个按钮关联控件变量:
-
在onInitDialog中设置图标:
BOOL CCameraLinkTestDlg::OnInitDialog()
{
m_preBT.SetIcon(IDI_ICON2);
m_next.SetIcon(IDI_ICON1);
m_saveBT.SetIcon(IDI_ICON3);
m_receiveBT.SetIcon(IDI_ICON4);
m_verticallyBT.SetIcon(IDI_ICON5);
m_leftBT.SetIcon(IDI_ICON6);
m_rightBT.SetIcon(IDI_ICON7);
m_horizontalBT.SetIcon(IDI_ICON8);
//鼠标放在按钮内时的背景色
m_preBT.SetColor(CButtonST::BTNST_COLOR_BK_IN, RGB(255, 255, 255));
//鼠标放在按钮内时的前景色
//m_btnST.SetColor(CButtonST::BTNST_COLOR_FG_IN, RGB(72, 118, 255));
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
六、设置图标
- 将使用的icon图标添加到本项目的res文件夹中
- 导入到icon资源视图中
- 在CCameraLinkTestDlg函数中改变图标ID
CCameraLinkTestDlg::CCameraLinkTestDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_CAMERALINKTEST_DIALOG, pParent)
, m_histSize(50)
{
//IDI_ICON9: 标题ID
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON9);
......
......
}
七、改变组框外观
- 修改组框ID
IDC_IMGENHANCEMENT
IDC_CAPTURE
IDC_IMGROTATIONOP
IDC_PIXSHOW - 添加WM_CTLCOLOR
日后更…