问题描述:
由于需要,把一张图片加载到cv::Mat对象中(image), 并调用算法计算出一个特征向量(feature) 和一些关键点(std::vector
cv::Mat image = imread(...);
cv::Mat feature = algorithm.Calc(...);
std::vector ps = algorithm.Calc(...);
部分代码:
1. 写入:
int MTemplateFactory::New(const MTemplateFeature& feature)
{
MDatabaseArchive* archive = MDatabaseManager::getSingleton().GetArchive();
if (archive)
{
MString sql;
if (feature.GetColor() <= 0)
sql = MString::Format("insert into tabTemplate (name, branch_id, feature, image, keypoints) values ('%s', %d, ?, ?, ?)", feature.GetName(), feature.GetBranchId());
else
sql = MString::Format("insert into tabTemplate (name, branch_id, color, feature, image, keypoints) values ('%s', %d, %d, ?, ?, ?)", feature.GetName(), feature.GetBranchId(), feature.GetColor());
try
{
//- Prepare data
cv::Mat img = feature.GetImage();
cv::Mat f = feature.GetFeature();
std::vector ps = feature.GetKeyPoints();
//- Image.
wxMemoryBuffer buf1;
buf1.AppendData(&img.rows, 4); int type1 = img.type();
buf1.AppendData(&img.cols, 4); buf1.AppendData(&type1, 4);
buf1.AppendData(img.data, img.cols * img.rows * img.elemSize());
//- Feature.
wxMemoryBuffer buf2;
buf2.AppendData(&f.rows, 4); int type2 = img.type();
buf2.AppendData(&f.cols, 4); buf2.AppendData(&type2, 4);
buf2.AppendData(f.data, f.cols * f.rows * f.eleSize());
//- keyPoints.
wxMemoryBuffer buf3;
int eleSize = sizeof(cv::KeyPoint);
for (auto point : ps)
{
buf3.AppendData(&point, eleSize);
}
wxSQLite3Statement stmt = archive->PrepareStatement(sql);
stmt.Bind(1, buf2);
stmt.Bind(2, buf1);
stmt.Bind(3, buf3);
if (stmt.ExecuteUpdate() > 0)
return archive->ExecuteScalar("select MAX(id) from tabTemplate");
}
catch (wxSQLite3Exception& e)
{
throw MException(e.GetMessage());
}
catch (cv::Exception& e)
{
throw MException(e.msg);
}
}
return 0;
}
MTemplateArray MTemplateFactory::List()
{
MTemplateArray arr;
MDatabaseArchive* archive = MDatabaseManager::getSingleton().GetArchive();
if (archive)
{
try
{
wxSQLite3ResultSet res = archive->ExecuteQuery("select * from tabTemplate");
while (res.NextRow())
{
int id = res.GetInt(0);
MString name = res.GetString(1);
int branch_id = res.GetInt(2);
int colorId = res.GetInt(3);
wxMemoryBuffer f1, f2, f3;
res.GetBlob("image", f1);
res.GetBlob("feature", f2);
res.GetBlob("keypoints", f3);
if (f1.IsEmpty() == true || f2.IsEmpty() == true || f3.IsEmpty() == true)
{
throw MException(_("特征模版保存数据为空,无法创建对象!"));
}
cv::Mat&& img = MakeMat(f1);
cv::Mat&& feature = MakeMat(f2);
//- Parse keypoints data.
uchar* data = (uchar*)f3.GetData();
int len = f3.GetDataLen();
std::vector ps;
int eleSize = sizeof(cv::KeyPoint);
int cnt = len / eleSize;
for (int i = 0; i < cnt; i++)
{
cv::KeyPoint* p = (cv::KeyPoint*)(data + i * eleSize);
ps.push_back(cv::KeyPoint(*p));
}
//- Construct template feature object...
arr.push_back(MTemplateFeature(id, name, branch_id, colorId, img.clone(), feature.clone(), ps));
}
}
catch (cv::Exception &e)
{
throw MException(e.msg);
}
catch (wxSQLite3Exception& e)
{
throw MException(e.GetMessage());
}
}
return arr;
}
cv::Mat MTemplateFactory::MakeMat(const wxMemoryBuffer& buf )
{
assert(buf.IsEmpty() == false);
void* data = buf.GetData();
int len = buf.GetDataLen();
int* p = (int*)data;
int h = p[0];
int w = p[1];
int _type = p[2]; int offset = sizeof(int) * 3;
return cv::Mat(h, w, _type, (uchar*)data + offset);
}
Sqlite3 存取二进制的文章很多,不记录了。wxSqlite3对blob的操作在wxSqlite3Statement类中,有类似绑定数据(Bind...)和提交操作(ExecuteUpdate...)的函数,具体查看相应的文档或者看源码有注释的。关于KeyPoint的保存,由于cv::KeyPoint这个类的所有数据成员全部都是实体数据,比如int, float 这样的数据,那么直接可以把每个cv::KeyPoint对象的地址加上长度( int len = sizeof(cv::KeyPoint) )存入即可,读数据库还原的时候只需 获取当该片内存,强制转换成 cv::KeyPoint* 就行了,但是如果某些情况,比如对象的成员变量里面有指针指向了另外的地址上的数据,那么这样行不通,强转后的这些指针因为环境变化而无效,如果操作程序会崩溃掉的。