XaiJu
patronizeme
patronizeme

patreon


Block-Matching Algorithm



import gifAnimation.*;





//Checkerbox checking on All


//ALMOST ALL DROPPED BLOCKS ARE IN THE LAST BIT OF COUNTING





//variables for tuning and changing below

int read = 3;//controls whether getVec et al. are called or drawing

boolean record = false;//should frames be saved?

float badS = 13000;//if final score is greater than this, square isn't drawn

int skip = 1;//how many frames to add: 1 for every frame of gif, w/ no sikpping;

//>1 to skip some frames

float mult = .5;//how far to go each move();

int blockS = 32; //square/block sidelength

int p = 23;//controls 2d logarithmic

//lastL is hopefully the number of blocks

int search = 20;//controls exhaustive search: p & search are half-sized




//variables you should tune above; vars you probably don't want to change below


int kj = 0; //frame #




int beat = 1000000;//maybe has to beat (be lower than) this to move? idk lol 300 is highest


boolean[] bad;//default is false

int images = 0; //image counter

//boolean fin = true;//we want frames to be consistent; search for fin lines

//and uncomment/fuck around to get them percentage-based


int sq = blockS*blockS;

int row = floor(width/blockS);

int lastL = 500*500/sq;//don't change: based on block size and canvas size



float[] score;




PVector[] locA;

PVector[] velO;

PVector[] vel1;


PVector[] init;




PImage[] xt;

PImage[] save;

PImage blank;

PImage blank1;


int counter = 0;//draw #


//PVector[] to = new PVector[lastL];



color[] col1 = new color[500*500];


color[] col3;



void setup() {

  background(0);

  size(500, 500);

  //fullScreen();

  println("LoadingGifs");

  xt = Gif.getPImages(this, "C:/Users/Com/Desktop/mi.gif");

  save = Gif.getPImages(this, "C:/Users/Com/Desktop/mi.gif");

  blank = loadImage("C:/Users/Com/Desktop/g.gif");

  blank1 = loadImage("C:/Users/Com/Desktop/g.gif");

  colorMode(HSB, 100, 100, 100);

  //stroke(30);

  //rectMode(CENTER);

  //strokeWeight(1);

  //frameRate(1);

  

  

  println("CountingBlocks");

  blockNum();

  println("Resizing");

  resizer();

}



void draw() {

  //delay(1000);

  //println("count", counter);

  println("kj", kj);

  println("imageCount", images);







  if (counter%read==0) {  //every so counter move to the next frame



    kj=kj+skip;



    if (kj>=xt.length-skip) {

      kj=0;


      //exit();

    }


    //image(save[kj], 0, 0);

    //background(0);






    

    println("ComparingAndGettingVector");

    getVec();


    //println("SmoothingVectors");

    //smoother();


    



    

    println("kj", kj);

    println("imageCount", images);

  }




  //background(0,0,99);

  //background(0);

  else {

    println("DrawingRects");

    move();//move blocks by fractions of full vector

    println("ReloadingImage");

    loadBlank();

    println("kj", kj);

    println("imageCount", images);

    

    

    if (record && images<100) {//save up to so many frames

      

      images++;

      saveFrame("frame-####.png");

    }

  

  }


  

  counter++;

}



void mouseClicked() {

  save("key.jpg");

  noLoop();

  println("Save&Stop");

}



void keyPressed() {

  loop();

  println("Go");

}



void loadBlank() {

  xt[kj].loadPixels();

  save[kj].loadPixels();

  for (int j = 0; j<save[kj].pixels.length; j++) {

    xt[kj].pixels[j] = save[kj].pixels[j];

  }

  xt[kj].updatePixels();

}



void blockNum() {

  lastL = 0;

  for (int y = 0; y+blockS<height; y=y+blockS) {

    for (int x = 0; x+blockS<width; x=x+blockS) {

      lastL++;

    }

  }

}



void getVecAll() {

  velO = new PVector [lastL];

  locA = new PVector [lastL];

  init = new PVector[lastL];

  col3 = new color[lastL];

  score = new float[lastL];

  bad = new boolean[lastL];



  save[kj+skip].loadPixels();

  save[kj].loadPixels();

  int match = 0;//squares processed

  int matchD = 0; //dropped squares

  int q = 0;// number of blocks

  int per = 0;

  for (int y = 0; y+blockS<width; y=y+blockS) {

    for (int x = 0; x+blockS<height; x=x+blockS) {

      int oneD1 = x+y*save[kj].width;

      int best = x+y*save[kj].width;

      float rec = beat;

      if (100*(match+matchD)/(lastL+1)!=per) {

        per = 100*(match+matchD)/(lastL+1);

        println("PercentProcessed", per);

        println("PercentDropped", 100*(matchD)/(lastL+1));

      }




          color[] lum1 = new color[sq];

      int z = 0;

      for (int l = 0; l<blockS; l=l+2) {

        for (int m = 0; m<blockS; m=m+2) {

          int oneD = constrain(m+x+(l+y)*save[kj].width, 0, save[kj].width*save[kj].height-1);

          lum1[z] = color(save[kj].pixels[oneD]);

          z++;

        }

      }

          





      for (int y1 =-search; y1<search; y1++) {

        for (int x1=-search; x1<search; x1++) {

          int att = oneD1+x1+y1*save[kj].width;

          float  d =0;

            int t = 0;

            //should just make this a function but whatere

            for (int y3 = 0; y3<blockS; y3=y3+2) {

              for (int x3 = 0; x3<blockS; x3=x3+2) {

                int oneD3 = constrain(att+x3+y3*save[kj].width, 0, save[kj].width*save[kj].height-1);


                d = d + abs(hue(save[kj+skip].pixels[oneD3])-hue(lum1[t])) + abs(saturation(save[kj+skip].pixels[oneD3])-saturation(lum1[t])) + abs(brightness(save[kj+skip].pixels[oneD3])-brightness(lum1[t]));

                t++;

              }

            }

            float score = d/t;



          if (score<rec) {

            rec = score;

            best = att;

          }


        }

      }




      PVector to1 = new PVector(best%save[kj].width, int(best/save[kj].width));

      PVector pos = new PVector(oneD1%save[kj].width, int(oneD1/save[kj].width));


      to1 = PVector.sub(to1,pos);





      if (rec > badS || to1.mag()>=400) {

        bad[q] = true;

        matchD++;

      } else {

        match++;

        strokeWeight(1);

        stroke(360,99,99);

        line(oneD1%save[kj].width,int(oneD1/save[kj].width),best%save[kj].width,int(best/save[kj].width));


      }




      //println("rec",rec);


      //mage looks good, as does to1


      to1.mult(mult);





      velO[q] = to1;



      //println("rec",rec);


      //col3[q] = col1[n]];

      locA[q] = pos;

      init[q] = pos;

      q++;

    }

  }



}



void getVec() {

  velO = new PVector [lastL];

  locA = new PVector [lastL];

  init = new PVector[lastL];

  col3 = new color[lastL];

  score = new float[lastL];

  bad = new boolean[lastL];

  

  save[kj+skip].loadPixels();

  save[kj].loadPixels();

  //loop through the center of blocks while applying the 2-d logarithmic search

  int match = 0;//squares processed

  int matchD = 0; //dropped squares

  int q = 0;// number of blocks

  int per = 0;

  for (int y = 0; y+blockS<width; y=y+blockS) {

    for (int x = 0; x+blockS<height; x=x+blockS) {


      color[] lum1 = new color[sq];

      int z = 0;

      for (int l = 0; l<blockS; l++) {

        for (int m = 0; m<blockS; m++) {

          int oneD = constrain(m+x+(l+y)*save[kj].width, 0, save[kj].width*save[kj].height-1);

          lum1[z] = color(save[kj].pixels[oneD]);

          z++;

        }

      }



      if (100*(match+matchD)/(lastL+1)!=per) {

        per = 100*(match+matchD)/(lastL+1);

        println("PercentProcessed", per);

        println("PercentDropped", 100*(matchD)/(lastL+1));

        

        

        

      }

      int s = p;


      int best = x+y*save[kj].width;

      int oneD1 = best;

      float rec = beat;//score will always be lower than 300?

      //start by comparing to self in next frame, then compare to others

      while (s>=1) {//two-step logarithmic

        int x1 = best%save[kj].width;

        int y1 = int(best/save[kj].width);


        if (s <= 1) {

          int att = best;

          int[] mover = {-save[kj].width, save[kj].width, 1, -1, save[kj].width+1, -save[kj].width-1, -save[kj].width+1, save[kj].width-1, 0};

          for (int j=0; j<mover.length; j++) {

            att = constrain(best+mover[j], 0, save[kj].width*save[kj].height-1);

            float  d =0;

            int t = 0;

            //should just make this a function but whatere

            for (int y3 = 0; y3<blockS; y3++) {

              for (int x3 = 0; x3<blockS; x3++) {

                int oneD3 = constrain(att+x3+y3*save[kj].width, 0, save[kj].width*save[kj].height-1);


                d = d + abs(hue(save[kj+skip].pixels[oneD3])-hue(lum1[t])) + abs(saturation(save[kj+skip].pixels[oneD3])-saturation(lum1[t])) + abs(brightness(save[kj+skip].pixels[oneD3])-brightness(lum1[t]));

                t++;

              }

            }

            float score = d/t;


            if (score<=rec) {

              rec = score;

              best = att;

            }

          }


          s = 0;

          //println("score",rec);

          if (rec>badS) {

            matchD++;

            bad[q] = true;//should this be bad[to.length] or bad[to.length+1?

          }//if the best match is >100 different, set bad to true and turn square invisible

          else {

            match++;

          }

        } else {

          int[] anoD = new int[9];

          anoD[0] = x1+y1*save[kj].width;

          anoD[1] = x1+s+y1*save[kj].width;

          anoD[2] = x1-s+y1*save[kj].width;

          anoD[3] = x1+(y1+s)*save[kj].width;

          anoD[4] = x1+(y1-s)*save[kj].width;

          //loop through candidates and find the closest

          //corners

          anoD[5] = x1+s+(y1+s)*save[kj].width;

          anoD[6] = x1+s+(y1-s)*save[kj].width;

          anoD[7] = x1-s+(y1+s)*save[kj].width;

          anoD[8] = x1-s+(y1-s)*save[kj].width;


          for (int n = 0; n<anoD.length; n++) {

            int att = constrain(anoD[n], 0, save[kj].width*save[kj].height-1);

            

            float  d =0;

            int t = 0;

            for (int y3 = 0; y3<blockS; y3++) {

              for (int x3 = 0; x3<blockS; x3++) {

                int oneD3 = constrain(att+x3+y3*save[kj].width, 0, save[kj].width*save[kj].height-1);


                d = d + abs(hue(save[kj+skip].pixels[oneD3])-hue(lum1[t])) + abs(saturation(save[kj+skip].pixels[oneD3])-saturation(lum1[t])) + abs(brightness(save[kj+skip].pixels[oneD3])-brightness(lum1[t]));

                t++;

              }

            }

            float score = d/t;

            

            if (score<rec) {

              rec = score;

              best = att;

            }

          }


          //if (best == anoD[0]) {

            s = s/2;

          //}

        }

      }



      PVector to1 = new PVector(best%save[kj].width, int(best/save[kj].width));

      PVector pos = new PVector(oneD1%save[kj].width, int(oneD1/save[kj].width));


      to1 = PVector.sub(to1, pos);



      //BELOW MIGHT NEED TO1 AND POS SWITCHED.


      if (to1.mag()>=400) {

        bad[q] = true;

        matchD++;

        match--;

      } 



      if (!bad[q]) {

        strokeWeight(1);

        stroke(360, 99, 99);

        line(oneD1%save[kj].width, int(oneD1/save[kj].width), best%save[kj].width, int(best/save[kj].width));

      }




      

      

      

      //mage looks good, as does to1


      to1.mult(mult);



      


      velO[q] = to1;



      //println("rec",rec);


      //col3[q] = col1[n]];

      locA[q] = pos;

      init[q] = pos;

      

      score[q] = rec;

      

      q++;

    }

  }

}



void smoother(){

  for(int n  = 0; n<lastL; n++){

    FloatList direc = new FloatList();

    FloatList far = new FloatList();

    int[] adjacent = {n+row,n-row,n+1,n-1,n+row-1,n+row+1,n-row+1,n-row-1};

    for(int j = 0; j<adjacent.length; j++){

      direc.append(degrees(velO[constrain(adjacent[j],0,lastL-1)].heading()));

      far.append(velO[constrain(adjacent[j],0,lastL-1)].mag());

    }

    far.sort();

    direc.sort();//I really don't want to sort and then have to loop to find the right one

    int mid = -1;

    int mid1 = -1;

    for(int j = 0; j<adjacent.length; j++){

      if(degrees(velO[constrain(adjacent[j],0,lastL-1)].heading()) == direc.get(4)){

        mid = constrain(adjacent[j],0,lastL-1);

      }

      if(velO[constrain(adjacent[j],0,lastL-1)].mag() == far.get(4)){

        mid1 = constrain(adjacent[j],0,lastL-1);

      }

    }

    

    if(far.max() <= velO[n].mag() || far.min() >= velO[n].mag()){

      velO[n] = velO[mid1];

      

    }

    if(direc.max() <= degrees(velO[n].heading()) || direc.min() >= degrees(velO[n].heading())){

      velO[n] = velO[mid];

    }

    

    

  }

}




void resizer(){

  int wid = width-width%blockS;

  int leng = height-height%blockS;

  for(int n =0; n<xt.length; n++){

    xt[n].resize(wid,leng);

    save[n].resize(wid,leng);

  }

  

}




void move() {



  int  d = 0;

  int per = 0;

  xt[kj+skip].loadPixels();

  save[kj].loadPixels();

  for (int n = 0; n<lastL; n=n+1) {


    if (100*(d)/(lastL+1)!=per) {

      per = 100*(d)/(lastL+1);

      println("PercentDrawn", per);

    }

    //if(locA[n] == null){

    //   bad[n] = true;

    //   println("bad");

    //  }


    if (!bad[n]) {

      //go through all pixels and move them toward their to[oneD]; vector field?





      

      //if "smoothing" is on, change to vel1 

      locA[n] = PVector.add(locA[n], velO[n]);



      //copy(save[kj],round(init[n].x),round(init[n].y),blockS,blockS,round(pos1.x),round(pos1.y),blockS,blockS);




      for (int x = 0; x<blockS; x++) {

        for (int y =0; y<blockS; y++) {

          int oneD = constrain(round(init[n].x)+round(init[n].y)*save[kj].width+x+y*save[kj].width, 0, save[kj].width*save[kj].height-1);

          int anoD = constrain(round(locA[n].x)+round(locA[n].y)*save[kj].width+x+y*save[kj].width, 0, save[kj].width*save[kj].height-1);


          xt[kj].pixels[anoD] = color(hue(save[kj+skip].pixels[oneD]), saturation(save[kj+skip].pixels[oneD]), brightness(save[kj+skip].pixels[oneD]));

        }

      }



      //stroke(color(hue(col3[n]),saturation(col3[n]),brightness(col3[n])));

      //fill(color(hue(col3[n]),saturation(col3[n]),brightness(col3[n])));

      //rect(pos1.x,pos1.y,blockS,blockS);

    }

    d++;

  }


  xt[kj].updatePixels();

  image(xt[kj], 0, 0);



  col1 = new color[lastL];

}


More Creators