Block-Matching Algorithm
Added 2017-06-30 01:19:19 +0000 UTCimport 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];
}