在某項目中,需要在前端相機中做人臉比對,因此需要在前端相機中增加一個人臉底庫,人臉底庫由uuid和人臉特征值組成。其中特征值為512個float數據,移植sqlite用來保存底庫信息,首先寫了一個demo,驗證可行性之后應用到實際項目中
sqlite3 * db= NULL; int rc = 0; char * sql = new char[800];//這個要適當的申請大一點,要不然不夠用。 char * zErrMsg = NULL; string id1 = "aaa";//用來模擬32位的uuid. std::vector<float> feature1{0.12, 0.23, 0.34, 0.45, 0.56, 0.67};//用來模擬512個人臉特征值. string id2 = "bbb";//用來模擬32位的uuid. std::vector<float> feature2{1.12, 1.23, 1.34, 1.45, 1.56, 1.67};//用來模擬512個人臉特征值. string id3 = "ccc";//用來模擬32位的uuid. std::vector<float> feature3{2.12, 2.23, 2.34, 2.45, 2.56, 2.67};//用來模擬512個人臉特征值. string id4 = "ddd";//用來模擬32位的uuid. std::vector<float> feature4{3.12, 3.23, 3.34, 3.45, 3.56, 3.67};//用來模擬512個人臉特征值. //先把人臉特征值的float數組轉成json,然后保存到數據庫中。cjson的源碼和例程在你自己的github上保存了 cJSON *root1, *js_feature1; root1 = cJSON_CreateObject(); cJSON_AddItemToObject(root1, "face_feature1", js_feature1 = cJSON_CreateArray()); for(int i = 0; i < feature1.size(); i++) { cJSON_AddItemToArray(js_feature1, cJSON_CreateNumber(feature1.at(i))); } char *s1 = cJSON_PrintUnformatted(root1); printf("s1:%s\n", s1); //先把人臉特征值的float數組轉成json,然后保存到數據庫中。cjson的源碼和例程在你自己的github上保存了 cJSON *root2, *js_feature2; root2 = cJSON_CreateObject(); cJSON_AddItemToObject(root2, "face_feature2", js_feature2 = cJSON_CreateArray()); for(int i = 0; i < feature2.size(); i++) { cJSON_AddItemToArray(js_feature2, cJSON_CreateNumber(feature2.at(i))); } char *s2 = cJSON_PrintUnformatted(root2); printf("s2:%s\n", s2); //先把人臉特征值的float數組轉成json,然后保存到數據庫中。cjson的源碼和例程在你自己的github上保存了 cJSON *root3, *js_feature3; root3 = cJSON_CreateObject(); cJSON_AddItemToObject(root3, "face_feature3", js_feature3 = cJSON_CreateArray()); for(int i = 0; i < feature3.size(); i++) { cJSON_AddItemToArray(js_feature3, cJSON_CreateNumber(feature3.at(i))); } char *s3 = cJSON_PrintUnformatted(root3); printf("s2:%s\n", s3); //先把人臉特征值的float數組轉成json,然后保存到數據庫中。cjson的源碼和例程在你自己的github上保存了 cJSON *root4, *js_feature4; root4 = cJSON_CreateObject(); cJSON_AddItemToObject(root4, "face_feature4", js_feature4 = cJSON_CreateArray()); for(int i = 0; i < feature4.size(); i++) { cJSON_AddItemToArray(js_feature4, cJSON_CreateNumber(feature4.at(i))); } char *s4 = cJSON_PrintUnformatted(root4); printf("s2:%s\n", s4); sqlite3_initialize(); rc = sqlite3_open_v2("featureList.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);//這時候登錄嵌入式設備,你會看見創建了一個featureList.db的文件。 if(rc != SQLITE_OK) { sqlite3_close_v2(db); printf("open featureList sql fail\n"); } else { printf("open featureList sql success\n"); } //這里的table名字featureList為前面open函數時的名字featureList, sprintf(sql, "CREATE TABLE featureList(ID INTEGER PRIMARY KEY AUTOINCREMENT, uuid VARCHAR(10),feature VARCHAR(10));"); sqlite3_exec(db, sql, 0, 0, &zErrMsg); //插入數據 //ID傳入NULL,那么會自動遞增,另外這里的%s要用單引號括起來, sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id1.c_str(), s1); sqlite3_exec( db , sql , 0 , 0 , &zErrMsg ); //ID傳入NULL,那么會自動遞增,另外這里的%s要用單引號括起來, sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id2.c_str(), s2); sqlite3_exec( db , sql , 0 , 0 , &zErrMsg ); //ID傳入NULL,那么會自動遞增,另外這里的%s要用單引號括起來, sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id3.c_str(), s3); sqlite3_exec( db , sql , 0 , 0 , &zErrMsg ); //ID傳入NULL,那么會自動遞增,另外這里的%s要用單引號括起來, sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id4.c_str(), s4); sqlite3_exec( db , sql , 0 , 0 , &zErrMsg ); //查詢數據 int nrow = 0, ncolumn = 0; char **azResult; sprintf(sql, "SELECT * FROM featureList"); sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg ); printf("row:%d, column:%d\n", nrow, ncolumn); for(int i = 0; i < (nrow + 1)*ncolumn; i++) { /********************************************************************************************** 注意這里無論是ID,還是uuid,還是feature都是用%s打印的,那么說明雖然我們定義的時候ID是定義成了整型, 但是實際上里面保存的時候是按照字符類型保存的,經測試,如果用用%d打印那么打印出來的是49 50這種,也就是1,2的ASCII碼。 ***********************************************************************************************/ printf("azResult[%d] = %s\n", i, azResult[i]); } string deleteId = "3";//定義成string類型,不要定義成int類型, printf("deleteId:%s\n", deleteId.c_str()); sprintf(sql, "DELETE FROM featureList WHERE ID = %s", deleteId.c_str()); printf("delete sql is:%s\n", sql); rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg); if(rc == SQLITE_OK) { //作用是重新構建數據庫文件,回收空白空間,減小數據庫文件的大小。 printf("delete success\n"); } else { printf("delete fail!\n"); } /********************************************************************************** 如果本來的ID是1 2 3 4,我們把3刪除,那么ID變為1 2 4,UPDATE語句的作用是把ID重新排序成1 2 3. 剛開始這里寫的是ID>1,這樣是錯誤的,應該是從刪除的元素開始ID=ID-1,刪除元素前面的ID是不用改的。 sprintf(sql, "UPDATE featureList SET ID=ID-1 WHERE ID>1"); error ***********************************************************************************/ sprintf(sql, "UPDATE featureList SET ID=ID-1 WHERE ID>%s", deleteId.c_str()); rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg); //刪除之后再次查詢看刪除是否正常 sprintf(sql, "SELECT * FROM featureList"); sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg ); printf("row:%d, column:%d\n", nrow, ncolumn); for(int i = 0; i < (nrow + 1)*ncolumn; i++) { //注意這里是用%s打印的,雖然我們定義ID的時候是整型,但是實際上里面保存的時候是字符型的, printf("azResult[%d] = %s\n", i, azResult[i]); } //釋放空間 delete[] sql; sqlite3_free_table(azResult); sqlite3_close(db);
打印的log如下圖:
使用過程中遇到的問題:
>>用上面的語句創建的數據庫,uuid的類型是C++中string,而不是C語言中的char,
sprintf(sql, "CREATE TABLE featureList(ID INTEGER PRIMARY KEY AUTOINCREMENT, uuid VARCHAR(10),feature VARCHAR(10));");
sLabel = to_string(label); for(int i = 1; i <= nrow; i++) { printf("sLabel.c_str():%s\n", sLabel.c_str()); cout<<sLabel<<endl; printf("azResult[i*ncolumn + 1]:%s\n", azResult[i*ncolumn + 1]); printf("strlen(sLabel.c_str()):%d\n", strlen(sLabel.c_str())); printf("strlen(azResult[i*ncolumn + 1]):%d\n", strlen(azResult[i*ncolumn + 1]));
//if(sLabel.c_str() == azResult[i*ncolumn + 1]) //error if(sLabel == azResult[i*ncolumn + 1]) { deleteId = azResult[i*ncolumn]; printf("deleteId:%s\n", deleteId.c_str()); sprintf(sql, "DELETE FROM featureList WHERE ID = %s", deleteId.c_str()); printf("delete sql is:%s\n", sql); rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg); if(rc == SQLITE_OK) { printf("delete success\n"); } else { printf("delete fail!\n"); return -1; } } }
上面的代碼中,sLabel.c_str() 和 azResult[i*ncolumn + 1]用printf打印出來之后發現值是一樣的,但是下面的 if(sLabel.c_str() == azResult[i*ncolumn + 1])卻進不去,通過strlen發現兩者的長度不一樣,這是因為azResult[i*ncolumn + 1]是string類型,把if(sLabel.c_str() == azResult[i*ncolumn + 1])修改為if(sLabel == azResult[i*ncolumn + 1]),問題解決。
>>數據庫中保存中文信息
labelname = "電腦"; sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s','%s');", sLabel.c_str(), s, labelname.c_str()); //sLabel要用c語言中的字符串形式,不能用C++中的string類型。
就直接把中文賦值就好了,不需要進行相應的編碼轉換。