summaryrefslogtreecommitdiff
path: root/offsetProject/src/imageStore.h
diff options
context:
space:
mode:
authorTim Redfern <tim@eclectronics.org>2014-03-13 16:21:36 +0000
committerTim Redfern <tim@eclectronics.org>2014-03-13 16:21:36 +0000
commitc062e52ad21440b69ec7096e37b0fc3346465328 (patch)
tree726a88191e381fd13ede1f6d9f9d970f991efa4c /offsetProject/src/imageStore.h
parent95d6f9293939cfe068c0ab95ed4534e7982ff4ae (diff)
working with flann
Diffstat (limited to 'offsetProject/src/imageStore.h')
-rw-r--r--offsetProject/src/imageStore.h198
1 files changed, 110 insertions, 88 deletions
diff --git a/offsetProject/src/imageStore.h b/offsetProject/src/imageStore.h
index 5f30163..8d1b584 100644
--- a/offsetProject/src/imageStore.h
+++ b/offsetProject/src/imageStore.h
@@ -7,6 +7,10 @@
#include "ofMain.h"
#include "ofxJSONElement.h"
+#include "ofxOpenCv.h"
+//#include <opencv/include/opencv2/flann/flann.hpp>
+
+using namespace cvflann;
long ofToLong(const string& intString);
@@ -19,15 +23,39 @@ class imageStore : public ofThread{
std::string instagram_url;
ofxJSONElement response;
std::map<std::string,ofImage> images;
+ vector<ofImage*> imageptrs;
deque<std::string> to_update;
+ //Matrix<float> dataset; doesn't need to be retained?
+
+ //need to be able to add arbitrary data and keep it?
+ //see pucilar behaviour if we delete the data after indexing it
+ //we see some puzzling performance anomalies if we add data
+ //maybe rebuild the index rather than use index.addPoints()
+ //this way the data can be kept contiguously
+ //or maybe just get a pointer to vector data with an offset
+ vector<float> data;
+ //to begin, get a single point per image
+
+ //retain a pointer to the flann indexer
+ Index<L2<float> >* index;
+
+ //Index<L2<float> > index(dataset, cv::flann::KDTreeIndexParams(4));
+
imageStore(){
instagram_url = "https://api.instagram.com/v1/tags/tycleeson/media/recent?client_id=c1d74d701fdf4ddd9f8d30ee9e8f944b";
interval=5.00f;
ofImage img;
img.allocate(MAX_TILE_SIZE,MAX_TILE_SIZE,OF_IMAGE_COLOR);
+ img.clear();
+ img.setUseTexture(true);
+ img.update();
images["000000"]=img;
colours["000000"]=ofColor(0,0,0);
+
+ }
+ ~imageStore(){
+ delete index;
}
void set_interval(float _interval){
@@ -49,85 +77,66 @@ class imageStore : public ofThread{
//how to make the search algorithm faster and better
//http://www.semanticmetadata.net/lire/
- /*
- 1. The box nature of the image matching isn't appealing
- 2. The way that the images flip quickly isn't appealing
-
- can we improve this by changing the screen gradually in some way?
-
- search tree/ octree
-
- each node associates an image, start with a black image
-
- a node owns a volume of RGB space
-
- new image: determine which octant it lands in
- subdivide the octant in R, G or B and give half to each image
-
- Q: does this lead to the possibility that images end up in the wrong place?
-
- with the naive algorithm, we measure distance between the colours in RGB space
-
- it becomes a long process because the number of calculations increases exponentially
-
- space partitioning: we observe that the image will often be nearest to an image in the same box
- although it may not be if they are at the edges
-
- so at each level, each node of the tree contains a list of images
-
- we traverse the tree and try to find the lowest level box with a match
- if the lowest level box with a match has more than 1 we compute distance?
-
- a difference algorithm
- minimise the error
- this involves comparing every pixel though
-
- gpu?
-
- put every quarter of every image into an image tree
-
- every image has an entry on levels 1-8
- start at level 8 (most detailed)
- check the leaf node ie 10110101 01101001 00110101
- if there are 1 or more images here choose one
- if none go to the next level...
-
- ie 1011010 0110100 0011010
- if there are more than 1 images here find the nearest
- if there is 1 choose it
- if there are none go to the next level
-
- */
-
-
std::map<std::string,ofColor> colours;
ofImage& get_image(const ofColor& col){
//float shortest_dist=999999.0f;
int sd=1000;
ofImage& im=images.begin()->second;
- std::string s=images.begin()->first;
- for (map<string,ofImage>::iterator it=images.begin();it!=images.end();++it){
- ofColor& c=colours[it->first];
- int rd=c.v[0]-col.v[0];
- int gd=c.v[1]-col.v[1];
- int bd=c.v[2]-col.v[2];
- //float dist=pow((float)((rd*rd)+(gd*gd)+(bd*bd)),0.5);
- int dist=abs(rd)+abs(gd)+abs(bd);
- if (dist<sd){
- sd=dist;
- im=it->second;
- s=it->first;
- }
- }
+ if( lock() ){
+ std::string s=images.begin()->first;
+ for (map<string,ofImage>::iterator it=images.begin();it!=images.end();++it){
+ ofColor& c=colours[it->first];
+ int rd=c.v[0]-col.v[0];
+ int gd=c.v[1]-col.v[1];
+ int bd=c.v[2]-col.v[2];
+ //float dist=pow((float)((rd*rd)+(gd*gd)+(bd*bd)),0.5);
+ int dist=abs(rd)+abs(gd)+abs(bd);
+ if (dist<sd){
+ sd=dist;
+ im=it->second;
+ s=it->first;
+ }
+ }
+ unlock();
+ }
//cerr<<"got image "<<s<<endl;
return im;
}
+
+ ofImage& get_image(float r,float g,float b){
+ ofImage& im=images.begin()->second;
+ if( lock() ){
+ float* test=new float[3];
+ test[0]=r;
+ test[1]=g;
+ test[2]=b;
+ Matrix<float> query(test,1,3);
+ Matrix<int> indices(new int[1], query.rows, 1);
+ Matrix<float> dists(new float[1], query.rows, 1);
+ index->knnSearch(query, indices, dists, 1,SearchParams(4));
+ im=*imageptrs[*indices[0]];
+ //int i=rand()%imageptrs.size();
+ //im=images[imageptrs[i]];
+ //cerr<<"returning image "<<i<<endl;
+ unlock();
+ }
+ return im;
+ }
+
ofColor get_colour(const ofImage& _img){
ofImage img=_img;
img.resize(1,1);
return ofColor(img.getPixels()[0],img.getPixels()[1],img.getPixels()[2]);
}
+ void add_data(const ofImage& _img){
+ ofImage img=_img;
+ img.resize(1,1);
+ data.push_back(img.getPixels()[0]);
+ data.push_back(img.getPixels()[1]);
+ data.push_back(img.getPixels()[2]);
+ }
+
//--------------------------
void threadedFunction(){
@@ -135,32 +144,42 @@ class imageStore : public ofThread{
ofDirectory image_path(ofToString(IMAGE_STORE_SIZE)+"/");
cerr<<"image path: "<<image_path.getAbsolutePath()<<endl;
- if (image_path.exists()){
- image_path.listDir();
- cerr<<"image path found, "<<image_path.size()<<" images"<<endl;
- for (int i=0;i<image_path.size();i++){
- ofImage img;
- img.setUseTexture(false);
- img.loadImage(ofToString(IMAGE_STORE_SIZE)+"/"+image_path.getFiles()[i].getFileName());
- img.resize(MAX_TILE_SIZE,MAX_TILE_SIZE);
- if( lock() ){
- colours[image_path.getFiles()[i].getBaseName()]=get_colour(img);
+ if( lock() ){ //lock the thread while preparing the initial images
+ if (image_path.exists()){
+ image_path.listDir();
+ cerr<<"image path found, "<<image_path.size()<<" images"<<endl;
+ for (int i=0;i<image_path.size();i++){
+ ofImage img;
+ img.setUseTexture(false);
+ img.loadImage(ofToString(IMAGE_STORE_SIZE)+"/"+image_path.getFiles()[i].getFileName());
+ img.resize(MAX_TILE_SIZE,MAX_TILE_SIZE);
+
+ //colours[image_path.getFiles()[i].getBaseName()]=get_colour(img);
+ add_data(img);
images[image_path.getFiles()[i].getBaseName()]=img;
- cerr<<image_path.getFiles()[i].getBaseName()<<": "<<colours[image_path.getFiles()[i].getBaseName()]<<endl;
+ imageptrs.push_back(&images[image_path.getFiles()[i].getBaseName()]);
+ //cerr<<image_path.getFiles()[i].getBaseName()<<": "<<colours[image_path.getFiles()[i].getBaseName()]<<endl;
to_update.push_back(image_path.getFiles()[i].getBaseName());
- unlock();
+ }
}
+ else {
+ cerr<<"creating image path"<<endl;
+ image_path.create();
}
- }
- else {
- cerr<<"creating image path"<<endl;
- image_path.create();
+
+ //build the flann index
+ Matrix<float> dataset(&data[0],data.size()/3,3);
+ index= new Index<L2<float> >(dataset, KDTreeIndexParams(4));
+ index->buildIndex();
+
+ unlock();
}
cout << "Api: " << instagram_url<<endl;
while( isThreadRunning() != 0 ){
+ /*
cout<<"."<<std::flush;
if (!response.open(instagram_url)) {
@@ -192,6 +211,7 @@ class imageStore : public ofThread{
}
}
}
+ */
ofSleepMillis(interval * 1000);
}
}
@@ -214,13 +234,15 @@ class imageStore : public ofThread{
to_update.pop_front();
- //int drawcount=0;
- //for (map<string,ofImage>::iterator i=images.begin();i!=images.end();++i){
- // if(i->second.isUsingTexture()){
- // drawcount++;
- // }
- //}
- //cout<<"loaded "<<im<<" "<<ofToLong(im)%(long)(ofGetWidth()-images[im].getWidth()+1)<<","<<ofToLong(im)%(long)(ofGetHeight()-images[im].getHeight()+1)<<endl;
+ /*
+ int drawcount=0;
+ for (map<string,ofImage>::iterator i=images.begin();i!=images.end();++i){
+ if(i->second.isUsingTexture()){
+ drawcount++;
+ }
+ }
+ cout<<"loaded "<<im<<" "<<ofToLong(im)%(long)(ofGetWidth()-images[im].getWidth()+1)<<","<<ofToLong(im)%(long)(ofGetHeight()-images[im].getHeight()+1)<<endl;
+ */
}
unlock();
}