图像分类工具其他功能见:图像分类工具
文章涉及到StringAbout::开头的函数具体实现参考:string与Cstring字符串类型转换和其他操作总结
CProcessFile::开头的函数实现参考:文件读写操作工具类CProcessFile
MCountFile函数参考:MCountFile类,统计指定文件夹下包含某个字段文件数目
1.选择路径对话框
对话框设计:
IDD_STARTDIALOG DIALOGEX 0, 0, 269, 148
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "路径选择"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
PUSHBUTTON "选择",IDC_BUTTON1,214,38,32,14
PUSHBUTTON "选择",IDC_BUTTON2,214,78,32,14
LTEXT "待分类图片路径:",IDC_STATIC,17,23,65,8
EDITTEXT IDC_EDIT_ORIGIN,17,38,187,14,ES_AUTOHSCROLL
LTEXT "分类后图片路径:",IDC_STATIC,16,64,65,8
EDITTEXT IDC_EDIT_CLASSIFY,18,78,186,14,ES_AUTOHSCROLL
PUSHBUTTON "开始分类",IDC_BUTTON3,198,110,50,14
EDITTEXT IDC_EDIT3,47,110,40,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT4,133,110,40,14,ES_AUTOHSCROLL
LTEXT "图片宽:",IDC_STATIC,15,112,33,8
LTEXT "图片高:",IDC_STATIC,100,113,33,8
END
2.图像显示并分类对话框
设计
IDD_IMGCLASSIFICATION_DIALOG DIALOGEX 0, 0, 591, 282
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "ImgClassification"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
PUSHBUTTON "正常",IDC_BUTTON1,534,199,50,14
PUSHBUTTON "不正常",IDC_BUTTON2,534,219,50,14
CONTROL "",IDC_SHOWIMG_WITHLAYER,"Static",SS_BLACKFRAME | SS_NOTIFY,7,7,505,267
LTEXT "总数:",IDC_STATIC2,518,14,25,8
LTEXT "Static",IDC_STATIC3,521,29,55,8
LTEXT "正在处理:",IDC_STATIC4,519,44,41,8
LTEXT "Static",IDC_STATIC5,522,59,55,8
LTEXT "当前图片路径:",IDC_STATIC6,520,76,57,8
EDITTEXT IDC_EDIT1,521,92,56,72,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN
PUSHBUTTON "撤销",IDC_BUTTON3,533,241,50,14
END
【选择】按钮实现方法:
void CStartDialog::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
TCHAR szFolderPath[MAX_PATH] = {0};
CString strFolderPath = TEXT("");
BROWSEINFO sInfo;
::ZeroMemory(&sInfo, sizeof(BROWSEINFO));
sInfo.pidlRoot = 0;
sInfo.lpszTitle = _T("请选择待分类图片位置");
sInfo.ulFlags = BIF_RETURNONLYFSDIRS|BIF_EDITBOX|BIF_DONTGOBELOWDOMAIN;
sInfo.lpfn = NULL;
// 显示文件夹选择对话框
LPITEMIDLIST lpidlBrowse = ::SHBrowseForFolder(&sInfo);
if (lpidlBrowse != NULL)
{
// 取得文件夹名
if (::SHGetPathFromIDList(lpidlBrowse,szFolderPath))
{
strFolderPath = szFolderPath;
}
}
if(lpidlBrowse != NULL)
{
::CoTaskMemFree(lpidlBrowse);
}
m_OriginalImgPath=strFolderPath;
GetDlgItem(IDC_EDIT_ORIGIN)->SetWindowTextW(m_OriginalImgPath);
}
【正常】按钮双击事件响应方法
void CImgClassificationDlg::OnBnClickedButton1()
{
CString filePath=StringAbout::IsWithLastDiagonalbar(m_classifyPath)+"正常";
CString myPath=L"normal";
CString pngPath=StringAbout::IsWithLastDiagonalbar(m_classifyPath)+myPath;
SaveDataAndShowNext(filePath,pngPath,myPath);
}
【异常】按钮双击事件响应函数同【正常】大同小异,只是文件路径改为“异常”或“abnor”。
StringAbout::开头的函数参看:
【撤销】按钮双击事件函数实现:
void CImgClassificationDlg::OnBnClickedButton3()
{
// TODO: Add your control notification handler code here
if (m_vImgInfos.size()>0)
{
ImgInfo imgInfo=m_vImgInfos[m_vImgInfos.size()-1];
m_vImgInfos.pop_back();
//显示上一张OCT图片
m_num=imgInfo.img_num;
ShowOCTPng();
//删除分类路径中的文件
DeleteFile(imgInfo.m_octfilePath);
DeleteFile(imgInfo.m_octImgPath);
}
}
对话框中用到的变量定义:
CString m_origPath;
CString m_classifyPath;
vector m_vSrcImgPath;
CMyImgShow m_ImgShow;
BYTE m_DispColorMap[256][3]; // 颜色表
int** m_ppImgData;
int m_num;
int m_iImgDataW;
int m_iImgDataH;
string m_curImgPath;
vector m_vImgInfos;
SaveDataAndShowNext()函数实现代码:
void CImgClassificationDlg::SaveDataAndShowNext(CString filePath,CString pngPath,CString postfix)
{
CString m_octFilePath=GetOCTFilePath(filePath);
CString m_octPngPath=GetOCTImgPath(pngPath,postfix);
BYTE *pdata = new BYTE[m_iImgDataW * m_iImgDataH *3];
int k = 0;
//保存mtsd和png文件
MyDATA * pOctdata = new MyDATA;
memset(pOctdata,0,sizeof(MyDATA));
int iCount=3;
int iPos=0;
int iWNum = m_iImgDataW * 3;
for(int i = 0 ; i< m_iImgDataW; ++i)
{
iPos = i * iCount;
for(int j =0 ; j< m_iImgDataH ; ++j)
{
pOctdata->_pbyOCTDataBuffer[i * m_iImgDataH + j]=(BYTE)m_ppImgData[i][j];
k = j * iWNum + iPos;
pdata[k] =(BYTE)m_ppImgData[i][j];
pdata[k+1] =(BYTE)m_ppImgData[i][j];
pdata[k+2] = (BYTE)m_ppImgData[i][j];
}
}
DWORD dwWriteBytes = CProcessFile::WriteBinaryFile(pOctdata->_pbyOCTDataBuffer,
m_iImgDataW * m_iImgDataH, m_octFilePath);
SaveBMP(m_octPngPath,pdata,m_iImgDataW,m_iImgDataH,3);
ImgInfo imgInfo;
imgInfo.img_num=m_num;
imgInfo.m_octfilePath=m_octFilePath;
imgInfo.m_octImgPath=m_octPngPath;
m_vImgInfos.push_back(imgInfo);
delete pOctdata;
pOctdata = NULL;
delete pdata;
pdata = NULL;
//切换到下一张OCT图片
m_num++;
ShowOCTPng();
}
GetOctfilePath()
CString CImgClassificationDlg::GetOCTFilePath(CString filePath)
{
CString m_szFileName;
if(!PathIsDirectory(filePath))//判断路径是否存在
{
CreateDirectory(filePath,NULL);
//CreateMultiDir((const char*)StringAbout::toCharX(filePath));
}
int pos;
CString sleft,sright,stemp;
sright=StringAbout::toCString(m_curImgPath);
pos=sright.Find(_T("\\"));
while (pos!=-1)
{
stemp=sright.Left(pos+1);
sleft=sleft+stemp;
sright=sright.Right(sright.GetLength()-pos-1);
pos=sright.Find(_T("\\"));
}
m_szFileName=filePath+"\\"+stemp;
if(!PathIsDirectory(m_szFileName))//判断路径是否存在
{
CreateDirectory(m_szFileName,NULL);
//CreateMultiDir((const char*)StringAbout::toCharX(filePath));
}
m_szFileName=m_szFileName+sright;
return m_szFileName;
}
GetOCTImgPath()
CString CImgClassificationDlg::GetOCTImgPath(CString filePath,CString postfix)
{
CString m_szFileName;
if(!PathIsDirectory(filePath))//判断路径是否存在
{
CreateDirectory(filePath,NULL);
//CreateMultiDir((const char*)StringAbout::toCharX(filePath));
}
int pos;
CString sleft,sright,stemp;
sright=StringAbout::toCString(m_curImgPath);
pos=sright.Find(_T("\\"));
while (pos!=-1)
{
stemp=sright.Left(pos+1);
sleft=sleft+stemp;
sright=sright.Right(sright.GetLength()-pos-1);
pos=sright.Find(_T("\\"));
}
m_szFileName=filePath+"\\"+stemp;
if(!PathIsDirectory(m_szFileName))//判断路径是否存在
{
CreateDirectory(m_szFileName,NULL);
//CreateMultiDir((const char*)StringAbout::toCharX(filePath));
}
sright=StringAbout::ReplacePostFix(StringAbout::toString(sright),"jpg");
CString tmp=L"_"+postfix;
sright=StringAbout::ChangeFileName(StringAbout::toString(sright),StringAbout::toString(tmp));
m_szFileName=m_szFileName+sright;
return m_szFileName;
}
SaveBMP函数
// 函数名称: SaveBMP
// 功能: 根据位图数组生成一个位图
// 输入参数: fileName 所保存的位图名称(需加上扩展名)
// m_buf_tmp 位图数组
// nwidth nheight iCount 位图数组的宽度,高度,位数(注: 如24位位图 iCount 应为 3 )
// 返回值: 生成位图文件成功 TRUE 否则 FALSE
BOOL SaveBMP(const CString fileName, const BYTE * m_buf_tmp, const UINT nwidth, const UINT nheight, const UINT iCount )//huangguihualogo
{
// 参数验证
ASSERT( ! fileName.IsEmpty() && m_buf_tmp != NULL && nwidth > 0 && nheight > 0 && iCount > 0 );
bool bRVal = TRUE; // 返回值
BITMAPINFO *m_pBmpInfo = NULL;//位图信息结构
BYTE *pInfoBuffer = NULL;
ReSize1dDataPointer( pInfoBuffer , sizeof(BITMAPINFO));
if (pInfoBuffer)
{
// m_pBmpInfo即指向m_chBmpBuf缓冲区,用户可以自己分配BTIMAPINFO缓冲区
m_pBmpInfo = (BITMAPINFO *)pInfoBuffer;
//初始化BITMAPINFO 结构,此结构在保存bmp文件、显示采集图像时使用
m_pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
// 图像宽度,一般为输出窗口宽度
m_pBmpInfo->bmiHeader.biWidth = nwidth;
m_pBmpInfo->bmiHeader.biHeight = nheight;
// 图像位深度,
m_pBmpInfo->bmiHeader.biBitCount = iCount *8;
// 对于低于8位的位图,还应设置相应的位图调色板
m_pBmpInfo->bmiHeader.biPlanes = 1;
m_pBmpInfo->bmiHeader.biCompression = BI_RGB;
m_pBmpInfo->bmiHeader.biSizeImage = nwidth*nheight*iCount;
m_pBmpInfo->bmiHeader.biXPelsPerMeter = 0;
m_pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
m_pBmpInfo->bmiHeader.biClrUsed = 0;
m_pBmpInfo->bmiHeader.biClrImportant = 0;
BITMAPFILEHEADER bfh = {0};
DWORD dwImageSize = 0;
DWORD dwBytesRead = 0;
dwImageSize = nwidth * nheight * iCount; //计算图像大小,由视频输出窗口和视频格式确定
bfh.bfType = (WORD)'M' << 8 | 'B'; //定义文件类型
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //定义文件头大小
bfh.bfSize = bfh.bfOffBits + dwImageSize; //文件大小
try{
HANDLE hFile = ::CreateFile(fileName,
GENERIC_WRITE ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
bRVal = FALSE;
}
else
{
::WriteFile(hFile, &bfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL );
::WriteFile(hFile, m_pBmpInfo, sizeof(BITMAPINFOHEADER), &dwBytesRead, NULL );
::WriteFile(hFile, m_buf_tmp, dwImageSize, &dwBytesRead, NULL );
CloseHandle(hFile);
}
}
catch(...)
{
bRVal = FALSE;
}
ReSize1dDataPointer( pInfoBuffer, 0 );
}
else
{
bRVal = FALSE;
}
return bRVal;
}
showOctPng()
void CImgClassificationDlg::ShowOCTPng()
{
//显示OCT图片
if (m_numSetWindowText(mval);
mval.Format(L"%d",m_num+1);
GetDlgItem(IDC_STATIC5)->SetWindowText(mval);
mval=StringAbout::toCString(m_curImgPath)+L"\r\n";
GetDlgItem(IDC_EDIT1)->SetWindowText(mval);
ShowImageFromFile(StringAbout::toCString(m_curImgPath));
}else{
}
}
showImgFromFile
void CImgClassificationDlg::ShowImageFromFile(CString m_strImgPath)
{
CFileFind findFile;
if (!findFile.FindFile(m_strImgPath))
{
return;
}
MyDATA * pOctdata = new MyDATA;
memset(pOctdata,0,sizeof(MyDATA));
DWORD dwReadBytes = CProcessFile::ReadBinaryFile(&(pOctdata->_pbyOCTDataBuffer[0]),
m_iImgDataW * m_iImgDataH, m_strImgPath);
if(m_iImgDataW * m_iImgDataH != dwReadBytes )
{
return; //读取图形数据失败
}
if ( m_ppImgData != NULL)
ReSize2dDataPointer(m_ppImgData, m_iImgDataW, 0, 0);
ReSize2dDataPointer(m_ppImgData, 0, m_iImgDataW, m_iImgDataH);
// // 控件显示必须的赋值
HDC* phDC = m_ImgShow.InitShowDC();
m_ImgShow.m_iShowW = m_iImgDataW;
m_ImgShow.m_iShowH = m_iImgDataH;
//m_ImgShow.m_iScanMode=m_scanMode;
CDC* pDC = m_ImgShow.GetDC();
CRect rt;
m_ImgShow.GetClientRect(rt);
MakeNewColor(1, m_DispColorMap); // 生成新的颜色数据 0:彩色,1:黑白
for(int i = 0 ; i< m_iImgDataW; ++i)
{
for(int j =0 ; j< m_iImgDataH ; ++j)
{
m_ppImgData[i][j] = (int)(pOctdata->_pbyOCTDataBuffer[i * m_iImgDataH + j]);
}
}
// // 图像数据写到DC
CreateDispBmpData(pDC, rt, m_ppImgData, m_iImgDataW, m_iImgDataH, m_DispColorMap, phDC, TRUE);
m_ImgShow.ReleaseDC(pDC);
m_ImgShow.Invalidate();
delete pOctdata;
pOctdata = NULL;
}
CreateDispBmpData
//
/* 生成内存DC中的位图
* 参数: pDC DC源
* rc
* tmpdata
* RefShowW
* RefShowH
* MapColor
* hdcMem
* falg
*
*/
void CreateDispBmpData(CDC *pDC,CRect rc,int **tmpdata,int RefShowW,int RefShowH ,BYTE MapColor[256][3] , HDC *hdcMem
,bool falg)
{
if ( pDC == NULL || tmpdata == NULL || hdcMem == NULL )
return ;
int i,j;
int tmpw ,tmph;
//int Disp_W,Disp_H;
// 原数据大小的宽高
tmpw = RefShowW /2 *2;
tmph = RefShowH /2 *2;
#if 1
BYTE *pbyDisplayData = NULL;
ReSize1dDataPointer( pbyDisplayData , tmpw * tmph * 3);
if(!pbyDisplayData)
{
return;
}
for (i = 0; i < tmpw; i++ )
{
BYTE d;
for (j = 0; j < tmph ; j++)
{
d = tmpdata[i][j]; // data
int m = j *tmpw * 3 + i * 3;
pbyDisplayData[m] = MapColor[d][2];
pbyDisplayData[m + 1] = MapColor[d][1];
pbyDisplayData[m + 2] = MapColor[d][0];
}
}
HBITMAP hbmBMP = CreateCompatibleBitmap(pDC->m_hDC, tmpw, tmph );
HGDIOBJ holdBmp = ::SelectObject(*hdcMem, hbmBMP);
char image_info[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
BITMAPINFOHEADER *pbmiHeader = (BITMAPINFOHEADER*)image_info;
pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
pbmiHeader->biWidth = tmpw;
pbmiHeader->biHeight = tmph;
pbmiHeader->biPlanes = 1;
pbmiHeader->biBitCount = 24;
pbmiHeader->biCompression = BI_RGB;
pbmiHeader->biSizeImage = tmpw*tmph*3;
pbmiHeader->biXPelsPerMeter = 0;
pbmiHeader->biYPelsPerMeter = 0;
pbmiHeader->biClrUsed = 0;
pbmiHeader->biClrImportant = 0;
SetDIBits(*hdcMem, hbmBMP, 0, pbmiHeader->biHeight, pbyDisplayData, (BITMAPINFO*)pbmiHeader, DIB_RGB_COLORS);
DeleteObject(hbmBMP);
ReSize1dDataPointer( pbyDisplayData , 0 );
#endif
}
初始化对话框
BOOL CImgClassificationDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
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);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
//对话框界面最大化
ShowWindow(SW_SHOWMAXIMIZED);
//CRect rect;
//GetClientRect(&rect); //取客户区大小
//old.x=rect.right-rect.left;
//old.y=rect.bottom-rect.top;
//获取文件路径
CGetFilePath mGetFilePath;
string path=StringAbout::toString(m_origPath);
//mGetFilePath.get_AllImg_Files(path,m_vSrcImgPath);
mGetFilePath.get_AllImg_FileNames(path,m_vSrcImgPath);
CString mval;
mval.Format(L"%d",(int)m_vSrcImgPath.size());
GetDlgItem(IDC_STATIC3)->SetWindowText(mval);
if (m_vSrcImgPath.size()>0)
{
m_curImgPath=m_vSrcImgPath[0];
mval.Format(L"%d",m_num+1);
GetDlgItem(IDC_STATIC5)->SetWindowText(mval);
mval=StringAbout::toCString(m_curImgPath)+L"\r\n";
GetDlgItem(IDC_EDIT1)->SetWindowText(mval);
//GetDlgItem(IDC_EDIT1)->SetWindowText(StringAbout::toCString(m_curImgPath));
ShowImageFromFile(StringAbout::toCString(m_vSrcImgPath[0]));
}else{
mval.Format(L"%d",m_num);
GetDlgItem(IDC_STATIC5)->SetWindowText(mval);
GetDlgItem(IDC_EDIT1)->SetWindowText(_T("没有找到图片文件"));
}
return TRUE; // return TRUE unless you set the focus to a control
}