OPENCV+VS2008+SQLserver 图片存储数据库开发 本人是做图像处理方向的,图像存储的数据库开发是一次尝试,开发平台用的是 OPENCV+VS2008+SQLserver , OPENCV 对图片的读取比较方便,而且支持 bmp , jpg , tiff , png 等多种图像格式,数据库访问技术采用
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, 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需要用户名和密码登陆的话,里面的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);
}

MySQL使用的是GPL許可證。 1)GPL許可證允許自由使用、修改和分發MySQL,但修改後的分發需遵循GPL。 2)商業許可證可避免公開修改,適合需要保密的商業應用。

選擇InnoDB而不是MyISAM的情況包括:1)需要事務支持,2)高並發環境,3)需要高數據一致性;反之,選擇MyISAM的情況包括:1)主要是讀操作,2)不需要事務支持。 InnoDB適合需要高數據一致性和事務處理的應用,如電商平台,而MyISAM適合讀密集型且無需事務的應用,如博客系統。

在MySQL中,外鍵的作用是建立表與表之間的關係,確保數據的一致性和完整性。外鍵通過引用完整性檢查和級聯操作維護數據的有效性,使用時需注意性能優化和避免常見錯誤。

MySQL中有四種主要的索引類型:B-Tree索引、哈希索引、全文索引和空間索引。 1.B-Tree索引適用於範圍查詢、排序和分組,適合在employees表的name列上創建。 2.哈希索引適用於等值查詢,適合在MEMORY存儲引擎的hash_table表的id列上創建。 3.全文索引用於文本搜索,適合在articles表的content列上創建。 4.空間索引用於地理空間查詢,適合在locations表的geom列上創建。

toCreateAnIndexinMysql,usethecReateIndexStatement.1)forasingLecolumn,使用“ createIndexIdx_lastNameEnemployees(lastName); 2)foracompositeIndex,使用“ createIndexIndexIndexIndexIndexDx_nameOmplayees(lastName,firstName,firstName);” 3)forauniqe instex,creationexexexexex,

MySQL和SQLite的主要區別在於設計理念和使用場景:1.MySQL適用於大型應用和企業級解決方案,支持高性能和高並發;2.SQLite適合移動應用和桌面軟件,輕量級且易於嵌入。

MySQL中的索引是數據庫表中一列或多列的有序結構,用於加速數據檢索。 1)索引通過減少掃描數據量提升查詢速度。 2)B-Tree索引利用平衡樹結構,適合範圍查詢和排序。 3)創建索引使用CREATEINDEX語句,如CREATEINDEXidx_customer_idONorders(customer_id)。 4)複合索引可優化多列查詢,如CREATEINDEXidx_customer_orderONorders(customer_id,order_date)。 5)使用EXPLAIN分析查詢計劃,避

在MySQL中使用事務可以確保數據一致性。 1)通過STARTTRANSACTION開始事務,執行SQL操作後用COMMIT提交或ROLLBACK回滾。 2)使用SAVEPOINT可以設置保存點,允許部分回滾。 3)性能優化建議包括縮短事務時間、避免大規模查詢和合理使用隔離級別。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Dreamweaver Mac版
視覺化網頁開發工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

Dreamweaver CS6
視覺化網頁開發工具