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

原创
2016-06-07 15:51:38 854浏览

OPENCV+VS2008+SQLserver 图片存储数据库开发 本人是做图像处理方向的,图像存储的数据库开发是一次尝试,开发平台用的是 OPENCV+VS2008+SQLserver , OPENCV 对图片的读取比较方便,而且支持 bmp , jpg , tiff , png 等多种图像格式,数据库访问技术采用

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

}

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。