OPENCV+VS2008+SQLserver图片存储数据库开发
2010-04-01 OPENCV+VS2008+SQLserver图片存储数据库开发 本人是做图像处理方向的,图像存储的数据库开发是一次尝试,开发平台用的是OPENCV+VS2008+SQLserver,OPENCV对图片的读取比较方便,而且支持bmp,jpg,tiff,png等多种图像格式,数据库访问技术采用的是ADO,下面我将详细的介绍整个开发过程。 第一步:安装opencv2.0并把cv.lib,cxcore.lib,highgui.lib 这三个库加入到工程里面,具体操作步骤参照http://www.opencv.org.cn/index.php/VC_2008_Express%E4%B8%8B%E5%AE%89%E8%A3%85OpenCV2.0。安装SQL2005,VS2008. 第二步:在SQL2005里新建一个新的数据库,名字为management,在management数据库中添加一个表,名字为personalmessage,字段有name,sex,student_number, Picture四个字段,前三个字段为字符型,后一个字段为image类型。 第三步:连接数据库,采用ADO方式 新建了一个类CADOConn,从Cobject派生,并增加以下四个成员函数: _RecordsetPtr? GetRecordset(_bstr_t bstrSQL,_bstr_t DB_Name);//得到命令对象指针 void ExitConnect();???????? //退出连接 BOOL OnInitADOConn(_bstr_t DB_Name);?? //初始化连接 BOOL Execute(_bstr_t bstrSQL,_bstr_t DB_Name);??? //执行sql语言 BOOL CADOConn::Execute(_bstr_t bstrSQL,_bstr_t DB_Name) { ???? try ???? { ???????? if (m_pConnection==NULL) ???????? OnInitADOConn(DB_Name); ???????? m_pConnection->Execute(bstrSQL,NULL,adCmdText); ???? //?? m_pConnection->Execute((LPCSTR)bstrSQL,adExecuteNoRecords); ? ???? } ???? catch (_com_error e) ???? { ???????? AfxMessageBox(e.ErrorMessage()); ???????? return false; ???? } ???? return TRUE; } BOOL CADOConn::OnInitADOConn(_bstr_t DB_Name) { ???? ::CoInitialize(NULL); ???? try ???? { ???????? m_pConnection.CreateInstance(__uuidof(Connection)); ???????? m_pConnection->PutCursorLocation(adUseClient); ???????? _bstr_t connectionstring = "Provider=sqloledb;Data Source="; ???????? connectionstring += _T("WIDOWSXP-CC3F79"); ???????? connectionstring += ";Initial Catalog="; ???????? connectionstring += DB_Name; ???????? connectionstring += ";User Id=sa"; ???????? connectionstring += ";Password=82877882"; ???????? connectionstring += ";"; ? ???????? m_pConnection->Open(connectionstring,"","",adConnectUnspecified); ???????? /*?? m_pConnection->ConnectionString="driver={SQL Server};server="";datebase="+DB_Name; ???????? m_pConnection->Open("","",NULL);*/ ???? } ? ???? catch (...) ???? { ???????? AfxMessageBox(_T("初始化出错")); ???????? return false; ???? } ???? return TRUE; } void CADOConn::ExitConnect() { ? ???? m_pConnection->Close(); ???? ::CoUninitialize(); } ? _RecordsetPtr CADOConn::GetRecordset(_bstr_t bstrSQL,_bstr_t DB_Name) { ? ???? try ???? { ???????? if(m_pConnection==NULL) ???????? OnInitADOConn(DB_Name); ???????? m_pRecordset.CreateInstance(__uuidof(Recordset)); ???????? m_pRecordset->Open(bstrSQL,_variant_t( (IDispatch *) m_pConnection,true),adOpenKeyset,adLockOptimistic,adCmdText); ???? } ???? catch (_com_error e) ???? { ???????? AfxMessageBox(e.ErrorMessage()); ???????? //return m_pRecordset=NULL; ???? } ???? return m_pRecordset; } 值得注意的是,在OnInitADOConn函数中,如果你的SQL需要用户名和密码登陆的话,里面的ID和password要对应你自己的SQL登录名和密码,Data Source也要特别注意,代表你数据库注册的服务器名,我的是WIDOWSXP-CC3F79。以后在程序中就可以直接调用GetRecordset来获得命令对象指针,从而可以方便的对数据库进行操作。 第四步:图片存入数据库 图片存入数据库的原理就是:把图片转换成二进制形式,存入到image变量中。 由于VC对bmp格式的图片处理比较方便,因此我用opencv读取完之后先把图片转换成bmp格式,读取二进制一般都是以文件形式读取,这里我投机取巧了一下,先把图片以bmp格式存放到某个路径中,然后用CFile以文件形式读取,存储到数据库之后再删除掉,删除用的是:CFile::Remove。如果大家有什么好方法还请告知,谢谢! 位图的读取可以参照http://www.programbbs.com/bbs/tree20-5675-29114.htm。 我的代码如下: void CadotestDlg::OnBnClickedadd() { ???? UpdateData(TRUE); ???? if(m_name!="") ???? { ???????? CString strSQL; ???????? CADOConn m_CAdoConn; ???????? _RecordsetPtr? m_pRecordset; ???????? //重新添加一个新的记录 ???????? strSQL=_T("select * from personalmessage"); ???????? m_pRecordset=m_CAdoConn.GetRecordset((_bstr_t)strSQL,(_bstr_t)("management")); ???????? m_pRecordset->AddNew(); ???????? m_pRecordset->PutCollect((_bstr_t)"name",(_bstr_t)m_name); ???????? m_pRecordset->PutCollect((_bstr_t)"sex",(_bstr_t)m_sex); ???????? m_pRecordset->PutCollect((_bstr_t)"student_number",(_bstr_t)m_student_number); ? ???????? if(m_pic1) ???????? { ????????????? cvSaveImage("D://SQL//adotest//adotest//1.bmp",m_pic1); ????????????? //保存在"management"数据库中的"personalmessage"表,字段名"picture" ????????????? CFile f; ????????????? // TODO: Add your control notification handler code here ????????????? CString? FilePathName("D://SQL//adotest//adotest//1.bmp"); ????????????? CFileException e; ????????????? if(f.Open(FilePathName,CFile::modeRead | CFile::typeBinary,&e)) ????????????? {??? ?????????????????? int nSize = f.GetLength();????????? //先得到文件长度 ?????????????????? BYTE * pBuffer = new BYTE [nSize];? //按文件的大小在堆上申请一块内存 ?????????????????? if (f.Read(pBuffer,nSize) > 0 )??? //把文件读到pBuffer(堆上申请一块内存) ?????????????????? {?? ?????????????????????? BYTE *pBuf = pBuffer;???? ///下面这一大段是把pBuffer里的数据放到库中 ?????????????????????? VARIANT??????????? varBLOB; ?????????????????????? SAFEARRAY???? *psa; ?????????????????????? SAFEARRAYBOUND???? rgsabound[1]; ? ?????????????????????? if(pBuf) ?????????????????????? {??? ??????????????????????????? rgsabound[0].lLbound = 0; ??????????????????????????? rgsabound[0].cElements = nSize; ??????????????????????????? psa = SafeArrayCreate(VT_UI1,1,rgsabound); ??????????????????????????? for (long i = 0; i < (long)nSize; i++) ???????????????????????????????? SafeArrayPutElement (psa,&i,pBuf++); ??????????????????????????? varBLOB.vt = VT_ARRAY | VT_UI1; ??????????????????????????? varBLOB.parray = psa; ??????????????????????????? m_pRecordset->GetFields()->GetItem("picture")->AppendChunk(varBLOB); ?????????????????????? } ?????????????????????? delete [] pBuffer;???? //删掉堆上申请的那一块内存 ?????????????????????? pBuf=0;??????????????? //以防二次乱用 ?????????????????? } ?????????????????? f.Close();??????????????? //这里一定要记得先关闭文件,后面再Remove,否则会出现共享冲突 ?????????????????? CFile::Remove( L"D://SQL//adotest//adotest//1.bmp" ); ? ????????????? } ????????????? m_pRecordset->Update(); ????????????? m_CAdoConn.ExitConnect(); ? ???????? } ???????? MessageBox(L"添加成功"); ???? } ???? else ???? { ???????? MessageBox(L"无信息添加"); ???? } ???? m_student_number=m_name=m_sex=""; ???? m_pic1=0; ???? UpdateData(FALSE); ? ? } 第五步:读取图片 代码如下: long nSize = m_pRecordset->GetFields()->GetItem("picture")->ActualSize; if(nSize > 0) ???????? { ????????????? _variant_t??? varBLOB; ????????????? varBLOB = m_pRecordset->GetFields()->GetItem("picture")->GetChunk(nSize); ????????????? if(varBLOB.vt == (VT_ARRAY | VT_UI1)) ????????????? { ?????????????????? if(BYTE *pBuffer = new BYTE [nSize+1])???????? ///重新申请必要的存储空间 ?????????????????? {??? ?????????????????????? char *pBuf = NULL; ?????????????????????? SafeArrayAccessData(varBLOB.parray,(void **)&pBuf); ?????????????????????? memcpy(pBuffer,pBuf,nSize);?????????????? ///复制数据到缓冲区m_pBMPBuffer ?????????????????????? SafeArrayUnaccessData (varBLOB.parray); ? ?????????????????????? delete [] pBuffer; ?????????????????????? pBuf=0; ? ?????????????????? } ?????????????????? //输出文件 ?????????????????? _variant_t varChunk; ?????????????????? HRESULT hr; ?????????????????? BYTE *pBuf = NULL;?? ?????????????????? pBuf = (BYTE*)GlobalAlloc(GMEM_FIXED,nSize); ?????????????????? SafeArrayAccessData(varBLOB.parray,(void **)&pBuf); ? ?????????????????? CFile outFile(L"D://SQL//adotest//adotest//2.bmp",CFile::modeCreate|CFile::modeWrite); ?????????????????? LPSTR buffer = (LPSTR)GlobalLock((HGLOBAL)pBuf); ?????????????????? outFile.Write(buffer,nSize); ?????????????????? GlobalUnlock((HGLOBAL)pBuf); ?????????????????? outFile.Close();?????????? ?????????????????? SafeArrayUnaccessData (varBLOB.parray); ????????????? } ????????????? IplImage *img=cvLoadImage("D://SQL//adotest//adotest//2.bmp"); ????????????? DrawPicToHDC(img,IDC_pic2); ????????????? m_pic2=img; ????????????? CFile::Remove( L"D://SQL//adotest//adotest//2.bmp" ); ???????? } 在整个过程中碰到的几个问题: 1. 在数据库读取过程中,如果某个记录为NULL的话,如果直接读取转换就会出错,所以得预先判断,代码如下: ???? VARIANT?? var?? =?? m_pRecordset->Fields->Item["name"]->GetValue();?? ???? if?? (?? var.vt?? !=?? VT_NULL?? )?? ???? {?? ???????? m_showname=(LPCTSTR)(_bstr_t)m_pRecordset->GetCollect((_bstr_t)"name"); ???? }?? 2. 文件打开之后要记得f.close(),否则就会出现共享冲突() 3. 图像显示在图像控件上的时候,定义的IplImage变量要记得初始化。 4. 载入的位图如果在文件中打开了rc就会出现opened in another editor,解决办法就是在文件视图中,把rc中的bmp关掉就OK了(这个问题因为我把一副图片设为了对话框的背景,然后把图片删除后造成的) 5. 还有就是几个变量类型转换的问题,像CString转 char*,_bstr_t与CString互转,我的程序里都有体现,另外一篇文章我也做了说明。 6. 图像的显示用的是 void CadotestDlg::DrawPicToHDC(IplImage *img,UINT ID)??????? //用于在ID所指定的窗口上显示图片 { ? ???? CDC *pDC = GetDlgItem(ID)->GetDC(); ???? HDC hDC= pDC->GetSafeHdc(); ???? CRect rect; ???? GetDlgItem(ID)->GetClientRect(&rect); ???? CvvImage cimg; ???? cimg.CopyOf(img); ???? cimg.DrawToHDC(hDC,&rect);? ???? ReleaseDC(pDC); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |