JNIEXPORT jboolean JNICALL Java_org_phash_MVPTree_add (JNIEnv *e, jobject ob, jobjectArray hashArray) { MVPFile mvpfile; jniHashType type; ph_mvp_init(&mvpfile); jsize len; if(hashArray == NULL || (len = e->GetArrayLength(hashArray)) == 0) return JNI_FALSE; jstring mvp = (jstring)e->GetObjectField(ob, e->GetFieldID(e->FindClass("org/phash/MVPTree"), "mvpFile", "Ljava/lang/String;")); mvpfile.filename = strdup(e->GetStringUTFChars(mvp, 0)); int i; jobject hashObj = e->GetObjectArrayElement(hashArray, 0); for(i = 0; i < sizeof(hashes)/sizeof(hashes[0]); i++) { if(e->IsInstanceOf(hashObj, *hashes[i].cl)) { mvpfile.hashdist = hashes[i].callback; mvpfile.hash_type = hashes[i].hashType; type = hashes[i].kind; break; } } const char *hash_file = NULL; DP **newHashes = (DP **)malloc(len*sizeof(DP *)); jintArray hashList = NULL; for(int j = 0; j < len; j++) { newHashes[j] = ph_malloc_datapoint(mvpfile.hash_type); hashObj = e->GetObjectArrayElement(hashArray, j); jstring hashStr = (jstring)e->GetObjectField(hashObj, hash_filename); hash_file = e->GetStringUTFChars(hashStr, 0); newHashes[j]->id = strdup(hash_file); e->ReleaseStringUTFChars(hashStr, hash_file); jint *hash_list = NULL; switch(type) { case IMAGE_HASH: { if(e->IsInstanceOf(hashObj, dctImClass)) { newHashes[j]->hash_length = 1; ulong64 hash = (ulong64)e->GetLongField(hashObj, dctImHash_hash); newHashes[j]->hash = (ulong64 *)malloc(sizeof(ulong64)); *(ulong64 *)newHashes[j]->hash = hash; } else if(e->IsInstanceOf(hashObj, mhImClass)) { jbyteArray h = (jbyteArray)e->GetObjectField(hashObj, mhImHash_hash); newHashes[j]->hash_length = e->GetArrayLength(h); jbyte *hash = e->GetByteArrayElements(h, NULL); newHashes[j]->hash = (uint8_t*)hash; } else if(e->IsInstanceOf(hashObj, radialImClass)) { jbyteArray h = (jbyteArray)e->GetObjectField(hashObj, radialImHash_hash); newHashes[j]->hash_length = e->GetArrayLength(h); jbyte *hash = e->GetByteArrayElements(h, NULL); newHashes[j]->hash = (uint8_t*)hash; } break; } case VIDEO_HASH: { jlongArray l = (jlongArray)e->GetObjectField(hashObj, vidHash_hash); newHashes[j]->hash_length = e->GetArrayLength(l); jlong *h = e->GetLongArrayElements(l, NULL); newHashes[j]->hash = (ulong64*)h; break; } case AUDIO_HASH: { hashList = (jintArray)e->GetObjectField(hashObj, audioHash_hash); newHashes[j]->hash_length = e->GetArrayLength(hashList); hash_list = e->GetIntArrayElements(hashList, NULL); newHashes[j]->hash = (uint32_t*)hash_list; break; } } } int nbsaved = 0; int res = ph_add_mvptree(&mvpfile, newHashes, len, nbsaved); for(int j = 0; j < len; j++) { if(type == AUDIO_HASH) { hashObj = e->GetObjectArrayElement(hashArray, j); hashList = (jintArray)e->GetObjectField(hashObj, audioHash_hash); e->ReleaseIntArrayElements(hashList, (jint *)newHashes[j]->hash, JNI_ABORT); } ph_free_datapoint(newHashes[j]); } e->ReleaseStringUTFChars(mvp, mvpfile.filename); free(newHashes); free(mvpfile.filename); return JNI_TRUE; }
JNIEXPORT jobjectArray JNICALL Java_org_phash_MVPTree_query (JNIEnv *e, jobject ob, jobject hashObj, jfloat radius, jfloat thresh, jint max) { MVPFile mvpfile; jniHashType type; ph_mvp_init(&mvpfile); jstring mvp = (jstring)e->GetObjectField(ob, e->GetFieldID(e->FindClass("org/phash/MVPTree"), "mvpFile", "Ljava/lang/String;")); mvpfile.filename = strdup(e->GetStringUTFChars(mvp, 0)); int i; for(i = 0; i < sizeof(hashes)/sizeof(hashes[0]); i++) { if(e->IsInstanceOf(hashObj, *hashes[i].cl)) { mvpfile.hashdist = hashes[i].callback; mvpfile.hash_type = hashes[i].hashType; type = hashes[i].kind; break; } } DP *query = ph_malloc_datapoint(mvpfile.hash_type); DP **results = (DP **)malloc(max*sizeof(DP *)); const char *hash_file = NULL; jstring hashStr = (jstring)e->GetObjectField(hashObj, hash_filename); hash_file = e->GetStringUTFChars(hashStr, 0); query->id = strdup(hash_file); int count = 0; jint *hash_list = NULL; jintArray hashList = NULL; switch(type) { case IMAGE_HASH: { if(e->IsInstanceOf(hashObj, dctImClass)) { query->hash_length = 1; ulong64 hash = (ulong64)e->GetLongField(hashObj, dctImHash_hash); query->hash = &hash; } else if(e->IsInstanceOf(hashObj, mhImClass) ) { jbyteArray hash = (jbyteArray)e->GetObjectField(hashObj, mhImHash_hash); query->hash_length = e->GetArrayLength(hash); jbyte *hashes = e->GetByteArrayElements(hash, NULL); query->hash = (uint8_t*)hashes; } else if(e->IsInstanceOf(hashObj, radialImClass) ) { jbyteArray hash = (jbyteArray)e->GetObjectField(hashObj, radialImHash_hash); query->hash_length = e->GetArrayLength(hash); jbyte *hashes = e->GetByteArrayElements(hash, NULL); query->hash = (uint8_t*)hashes; } break; } case VIDEO_HASH: { jlongArray l = (jlongArray)e->GetObjectField(hashObj, vidHash_hash); query->hash_length = e->GetArrayLength(l); jlong *h = e->GetLongArrayElements(l, NULL); query->hash = (ulong64*)h; break; } case AUDIO_HASH: { hashList = (jintArray)e->GetObjectField(hashObj, audioHash_hash); query->hash_length = e->GetArrayLength(hashList); hash_list = e->GetIntArrayElements(hashList, NULL); query->hash = (uint32_t*)hash_list; break; } } int res = ph_query_mvptree(&mvpfile, query, max, radius, thresh, results, count); if(type == AUDIO_HASH) e->ReleaseIntArrayElements(hashList, hash_list, JNI_ABORT); jobjectArray ret; if(res != 0) { ret = NULL; } else { jobject iobj = e->NewObject(*hashes[i].cl, *hashes[i].ctor); ret = e->NewObjectArray(count, *hashes[i].cl, iobj); for(int j = 0; j < count; j++) { jobject obj = e->NewObject(*hashes[i].cl, *hashes[i].ctor); jstring id = e->NewStringUTF(results[j]->id); e->SetObjectField(obj, hash_filename, id); switch(type) { case IMAGE_HASH: if(e->IsInstanceOf(obj, dctImClass)) e->SetLongField(obj, *hashes[i].hashID, *(jlong *)results[j]->hash); else if(e->IsInstanceOf(obj, mhImClass) || e->IsInstanceOf(obj, radialImClass)) { jbyteArray hash = e->NewByteArray(results[j]->hash_length); e->SetByteArrayRegion(hash, 0, results[j]->hash_length, (jbyte *)results[j]->hash); e->SetObjectField(obj, *hashes[i].hashID, hash); } break; case VIDEO_HASH: e->SetLongField(obj, *hashes[i].hashID, *(jlong *)results[j]->hash); break; case AUDIO_HASH: jintArray hashArray = e->NewIntArray(results[j]->hash_length); e->SetIntArrayRegion(hashArray, 0, results[j]->hash_length, (jint *)results[j]->hash); e->SetObjectField(obj, *hashes[i].hashID, hashArray); break; } e->SetObjectArrayElement(ret,j,obj); } } e->ReleaseStringUTFChars(mvp, mvpfile.filename); e->ReleaseStringUTFChars(hashStr, hash_file); ph_free_datapoint(query); for(int i = 0; i < count; i++) { if(results[i]) ph_free_datapoint(results[i]); } free(results); free(mvpfile.filename); return ret; }
int main(int argc, char **argv){ if (argc < 3){ printf("not enough input args\n"); printf("usage: %s directory dbname [radius] [knearest] [threshold]\n", argv[0]); return -1; } const char *dir_name = argv[1];/* name of files in directory of query images */ const char *filename = argv[2];/* name of file to save db */ MVPFile mvpfile; mvpfile.filename = strdup(filename); mvpfile.hashdist = distancefunc; mvpfile.hash_type = UINT64ARRAY; int nbfiles = 0; printf("using db %s\n", filename); printf("using dir %s for query files\n", dir_name); char **files = ph_readfilenames(dir_name,nbfiles); if (!files){ printf("unable to read files from directory\n"); return -2; } printf("nb query files = %d\n", nbfiles); DP *query = ph_malloc_datapoint(mvpfile.hash_type); if (query == NULL){ printf("mem alloc error\n"); return -3; } float radius = 30.0f; float threshold = 15.0f; int knearest = 20; if (argc >= 4){ radius = atof(argv[3]); } if (argc >= 5){ knearest = atoi(argv[4]); } if (argc >= 6){ threshold = atof(argv[5]); } printf("radius = %f\n", radius); printf("knearest = %d\n", knearest); printf("threshold = %f\n", threshold); DP **results = (DP**)malloc(knearest*sizeof(DP*)); if (results == NULL){ return -3; } ulong64 tmphash = 0x0000000000000000; int nbfound = 0, count = 0, sum_calcs = 0; for (int i=0;i<nbfiles;i++){ if (ph_dct_imagehash(files[i],tmphash) < 0){ printf("unable to get hash\n"); continue; } printf("query[%d]: %s %llx\n", i, files[i], tmphash); query->id = files[i]; query->hash = &tmphash; query->hash_length = 1; nb_calcs = 0; nbfound = 0; MVPRetCode retcode = ph_query_mvptree(&mvpfile,query,knearest,radius,threshold,results,nbfound); if (retcode != PH_SUCCESS && retcode != PH_ERRCAP){ printf("could not complete query, %d\n",retcode); continue; } count++; sum_calcs += nb_calcs; printf(" %d files found\n", nbfound); for (int j=0;j<nbfound;j++){ float d = distancefunc(query, results[j]); printf(" %d %s distance = %f\n", j, results[j]->id, d); } printf("nb distance calcs: %d\n", nb_calcs); for (int j=0;j<nbfound;j++){ free(results[j]->id); results[j]->id = NULL; free(results[j]->hash); results[j]->id = NULL; ph_free_datapoint(results[j]); } } float ave_calcs = (float)sum_calcs/(float)count; printf("ave calcs/query: %f\n", ave_calcs); for (int i=0;i<nbfiles;i++){ free(files[i]); } free(files); ph_free_datapoint(query); free(results); free(mvpfile.filename); return 0; }
JNIEXPORT jboolean JNICALL Java_org_phash_MVPTree_create (JNIEnv *e, jobject ob, jobjectArray hashArray) { jint hashLen; if(hashArray == NULL || (hashLen = e->GetArrayLength(hashArray)) == 0) return JNI_FALSE; jstring mvp = (jstring)e->GetObjectField(ob, e->GetFieldID(e->FindClass("org/phash/MVPTree"), "mvpFile", "Ljava/lang/String;")); MVPFile mvpfile; ph_mvp_init(&mvpfile); mvpfile.filename = strdup(e->GetStringUTFChars(mvp, 0)); jniHashType type; jobject htype = e->GetObjectArrayElement(hashArray, 0); for(int i = 0; i < sizeof(hashes)/sizeof(hashes[0]); i++) { if(e->IsInstanceOf(htype, *hashes[i].cl)) { mvpfile.hashdist = hashes[i].callback; mvpfile.hash_type = hashes[i].hashType; type = hashes[i].kind; break; } } DP **hashlist = (DP **)malloc(hashLen*sizeof(DP*)); for(jsize i = 0; i < hashLen; i++) { jobject hashObj = e->GetObjectArrayElement(hashArray, i); hashlist[i] = ph_malloc_datapoint(mvpfile.hash_type); if(!hashlist[i]) { free(hashlist); e->ReleaseStringUTFChars(mvp, mvpfile.filename); return JNI_FALSE; } jstring fname = (jstring)e->GetObjectField(hashObj, hash_filename); const char *path = e->GetStringUTFChars(fname, 0); hashlist[i]->id = strdup(path); switch(type) { case IMAGE_HASH: if(e->IsInstanceOf(hashObj, dctImClass)) { ulong64 tmphash; ph_dct_imagehash(path, tmphash); hashlist[i]->hash = (ulong64 *)malloc(sizeof(ulong64)); *(ulong64 *)hashlist[i]->hash = tmphash; hashlist[i]->hash_length = 1; } else if(e->IsInstanceOf(hashObj, mhImClass)) { int N; uint8_t *hash = ph_mh_imagehash(path, N); hashlist[i]->hash = hash; hashlist[i]->hash_length = N; } else if(e->IsInstanceOf(hashObj, radialImClass)) { Digest d; if(ph_image_digest(path, 1.0, 1.0, d, 180) >= 0) { hashlist[i]->hash = d.coeffs; hashlist[i]->hash_length = d.size; } } break; case VIDEO_HASH: { int len; ulong64 *vhash = ph_dct_videohash(path, len); if(!vhash) { for(int i = 0; i < hashLen; i++) { if(hashlist[i]) ph_free_datapoint(hashlist[i]); } free(hashlist); e->ReleaseStringUTFChars(mvp, mvpfile.filename); return JNI_FALSE; } hashlist[i]->hash = vhash; hashlist[i]->hash_length = len; } break; case AUDIO_HASH: const float threshold = 0.30; const int block_size = 256; const int sr = 8000; const int channels = 1; int nbframes, N; float *buf = ph_readaudio(path,sr,channels,NULL,N); if(buf) { uint32_t *audioHash = ph_audiohash(buf,N,sr,nbframes); free(buf); hashlist[i]->hash_length = nbframes; hashlist[i]->hash = audioHash; } else { free(hashlist); e->ReleaseStringUTFChars(mvp, mvpfile.filename); return JNI_FALSE; } break; } e->ReleaseStringUTFChars(fname, path); } MVPRetCode ret = ph_save_mvptree(&mvpfile, hashlist, hashLen); for(int i = 0; i < hashLen; i++) { if(hashlist[i]) { free(hashlist[i]->hash); free(hashlist[i]->id); } } free(hashlist); e->ReleaseStringUTFChars(mvp, mvpfile.filename); free(mvpfile.filename); return (int)ret; }
int main(int argc, char **argv){ if (argc < 3){ printf("not enough input args\n"); printf("usage: %s directory filename\n", argv[0]); return -1; } const char *dir_name = argv[1];/* name of dir to retrieve image files */ const char *filename = argv[2];/* name of file to save db */ MVPFile mvpfile; mvpfile.filename = strdup(filename); mvpfile.hashdist = distancefunc; mvpfile.hash_type = UINT64ARRAY; int nbfiles = 0; printf("dir name: %s\n", dir_name); char **files = ph_readfilenames(dir_name,nbfiles); if (!files){ printf("mem alloc error\n"); return -2; } printf("nbfiles = %d\n", nbfiles); DP **hashlist = (DP**)malloc(nbfiles*sizeof(DP*)); if (!hashlist){ printf("mem alloc error\n"); return -3; } int count = 0; ulong64 tmphash = 0; for (int i=0;i<nbfiles;i++){ hashlist[count] = ph_malloc_datapoint(mvpfile.hash_type); if (hashlist[count] == NULL){ printf("mem alloc error\n"); return -4; } hashlist[count]->hash = malloc(sizeof(ulong64)); if (hashlist[count]->hash == NULL){ printf("mem alloc error\n"); return -5; } printf("file[%d] = %s\n", i, files[i]); if (ph_dct_imagehash(files[i],tmphash) < 0){ printf("unable to get hash\n"); free(hashlist[count]->hash); ph_free_datapoint(hashlist[count]); continue; } hashlist[count]->id = files[i]; *((ulong64*)hashlist[count]->hash) = tmphash; hashlist[count]->hash_length = 1; count++; } printf("add files to file %s\n", filename); int nbsaved; MVPRetCode ret = ph_add_mvptree(&mvpfile, hashlist, count,nbsaved); printf("number saved %d out of %d, ret code %d\n", nbsaved,count,ret); for (int i=0;i<nbfiles;i++){ free(files[i]); } free(files); for (int i=0;i<nbfiles;i++){ free(hashlist[i]->hash); ph_free_datapoint(hashlist[i]); } free(hashlist); return 0; }