加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

OPENCV+VS2008+SQLserver图片存储数据库开发

发布时间:2020-12-12 15:22:49 所属栏目:MsSql教程 来源:网络整理
导读:2010-04-01 OPENCV+VS2008+SQLserver 图片存储数据库开发 本人是做图像处理方向的,图像存储的数据库开发是一次尝试,开发平台用的是 OPENCV+VS2008+SQLserver , OPENCV 对图片的读取比较方便,而且支持 bmp , jpg , tiff , png 等多种图像格式,数据库

2010-04-01

OPENCV+VS2008+SQLserver图片存储数据库开发

本人是做图像处理方向的,图像存储的数据库开发是一次尝试,开发平台用的是OPENCV+VS2008+SQLserverOPENCV对图片的读取比较方便,而且支持bmpjpgtiffpng等多种图像格式,数据库访问技术采用的是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。安装SQL2005VS2008.

第二步:SQL2005里新建一个新的数据库,名字为management,在management数据库中添加一个表,名字为personalmessage,字段有namesexstudent_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需要用户名和密码登陆的话,里面的IDpassword要对应你自己的SQL登录名和密码,Data Source也要特别注意,代表你数据库注册的服务器名,我的是WIDOWSXP-CC3F79。以后在程序中就可以直接调用GetRecordset来获得命令对象指针,从而可以方便的对数据库进行操作。

第四步:图片存入数据库

图片存入数据库的原理就是:把图片转换成二进制形式,存入到image变量中。

由于VCbmp格式的图片处理比较方便,因此我用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_tCString互转,我的程序里都有体现,另外一篇文章我也做了说明。

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);

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读