Alpha-0.33 Bugfixes, keepRatio & cut-off black

Fixed Bugs preventing correct execution including:
Erroneous slot calculations
Incorrect workload division for targetWorkers
Placing shrinked Versions (improved performance)

Also introduced:
keepRatio option - to only shrink Input while keeping their ratio
cutOut		 - cutting out unrasterized space on the target Image
(cutOut is only there to correct the flawed Rasterization)
dev
Peery 7 years ago
parent dc25d1f2ab
commit a873a0e096

@ -10,10 +10,10 @@ import peery.picture.ImageAnalyzer;
public class Mosaic extends Thread{ public class Mosaic extends Thread{
public static final String programmName = "Mosaic", public static final String programmName = "Mosaic",
versionString = "Alpha-0.32"; versionString = "Alpha-0.33";
private static final String outputName = "Output"; private static final String outputName = "Output";
private static final int gridX = 200, gridY = 200, targetMulti = 2, private static final int gridX = 100, gridY = 50, targetMulti = 2,
alphaThreshhold = 30, alphaThreshhold = 30,
adaptionCount = 300, adaptionCount = 300,
inputWorkerLimit = 10, inputWorkerLimit = 10,
@ -21,14 +21,14 @@ public class Mosaic extends Thread{
matchWorkerLimit = 10, matchWorkerLimit = 10,
placeWorkerLimit = 2; placeWorkerLimit = 2;
private static final double adaptionStep = 1.1, gridErrorThresh = 0.15; private static final double adaptionStep = 1.1, gridErrorThresh = 0.15;
private static boolean keepRatio = false;
/* /*
* *
* Performance: * Performance:
* *
* *
* FIX: * FIX:
* somewhere I'm loosing pixels from the target (the output is cut off as if it was smaller) * rasterization doesn't cover everything!
* investigate picture stretching -> is ImageUtils.resizeImage() even used?
* alphaThreshhold is currently dead * alphaThreshhold is currently dead
* *
* Feature: * Feature:
@ -42,7 +42,8 @@ public class Mosaic extends Thread{
public Mosaic(){ public Mosaic(){
fh = new FileHandler("resources"); fh = new FileHandler("resources");
Log.log(LogLevel.Info, "Starting "+programmName+" "+versionString); Log.log(LogLevel.Info, "Starting "+programmName+" "+versionString);
ia = new ImageAnalyzer(fh, inputWorkerLimit, targetWorkerLimit, matchWorkerLimit, placeWorkerLimit, alphaThreshhold); ia = new ImageAnalyzer(fh, inputWorkerLimit, targetWorkerLimit, matchWorkerLimit,
placeWorkerLimit, alphaThreshhold, keepRatio);
this.start(); this.start();
} }
@ -81,6 +82,7 @@ public class Mosaic extends Thread{
e.printStackTrace(); e.printStackTrace();
} }
} }
cutOutGrid();
Log.log.perfLog("Finished Placement!"); Log.log.perfLog("Finished Placement!");
Log.log(LogLevel.Info, "Finished placement. Output is done ..."); Log.log(LogLevel.Info, "Finished placement. Output is done ...");
Log.log.perfLog("Saving output to file ..."); Log.log.perfLog("Saving output to file ...");
@ -95,8 +97,8 @@ public class Mosaic extends Thread{
* Starts threads to index all not indexed images and rasterizes and classifies the Target. * Starts threads to index all not indexed images and rasterizes and classifies the Target.
*/ */
public void prepMatching(){ public void prepMatching(){
ia.updateIndex();
ia.rasterizeTarget(gridX, gridY, targetMulti, gridErrorThresh, adaptionCount, adaptionStep); ia.rasterizeTarget(gridX, gridY, targetMulti, gridErrorThresh, adaptionCount, adaptionStep);
ia.updateIndex();
ia.classifyTarget(); ia.classifyTarget();
} }
@ -110,6 +112,12 @@ public class Mosaic extends Thread{
ia.placeFragments(); ia.placeFragments();
} }
public void cutOutGrid(){
Log.log(LogLevel.Info, "Cutting out what the grid covered!");
Log.log(LogLevel.Debug, "Cutting out 0 0 "+ia.gridEnd[0]+" "+ia.gridEnd[1]);
ia.canvas = ia.canvas.getSubimage(0, 0, ia.gridEnd[0], ia.gridEnd[1]);
}
public static void main(String[] args){ public static void main(String[] args){
new Mosaic(); new Mosaic();
} }

@ -138,6 +138,7 @@ public class FileHandler {
+ " Attempted to write at "+file.getAbsolutePath()); + " Attempted to write at "+file.getAbsolutePath());
e.printStackTrace(); e.printStackTrace();
} }
Log.log(LogLevel.Info, "Saved "+file.getName()+" !");
} }
/** /**

@ -29,6 +29,8 @@ public class ImageAnalyzer {
private HashMap<String, Integer> index; private HashMap<String, Integer> index;
private int alphaThreshhold; private int alphaThreshhold;
public final boolean keepRatio;
public int[] gridEnd;
//Input Classification Worker //Input Classification Worker
private int inputWorkersLimit; private int inputWorkersLimit;
@ -57,10 +59,12 @@ public class ImageAnalyzer {
// //
public ImageAnalyzer(FileHandler fh, int inputWorkersLimit, int targetWorkersLimit, public ImageAnalyzer(FileHandler fh, int inputWorkersLimit, int targetWorkersLimit,
int matchWorkersLimit, int placeWorkersLimit, int alphaThreshhold){ int matchWorkersLimit, int placeWorkersLimit, int alphaThreshhold, boolean keepRatio){
this.fh = fh; this.fh = fh;
this.target = fh.loadImage(fh.TargetImageFile); this.target = fh.loadImage(fh.TargetImageFile);
this.alphaThreshhold = alphaThreshhold; this.alphaThreshhold = alphaThreshhold;
this.keepRatio = keepRatio;
this.gridEnd = new int[2];
this.inputWorkersLimit = inputWorkersLimit; this.inputWorkersLimit = inputWorkersLimit;
this.targetWorkersLimit = targetWorkersLimit; this.targetWorkersLimit = targetWorkersLimit;
@ -179,8 +183,9 @@ public class ImageAnalyzer {
*/ */
public void classifyTarget(){ public void classifyTarget(){
Log.log(LogLevel.Info, "Starting Target Classification. Calculating workload and spawning worker(s) ..."); Log.log(LogLevel.Info, "Starting Target Classification. Calculating workload and spawning worker(s) ...");
this.targetWorkers = new TargetImageAnalyzerWorker[targetWorkersLimit]; this.targetWorkers = new TargetImageAnalyzerWorker[targetWorkersLimit+1];
int workload = this.slotCount / this.targetWorkersLimit; Log.log(LogLevel.Debug, slotCount+" slot(s) need to be classified!");
int workload = this.slotCount / (this.targetWorkersLimit);
int initialWork = this.slotCount % workload; int initialWork = this.slotCount % workload;
int currWorker = 0; int currWorker = 0;
if(initialWork != 0){ if(initialWork != 0){
@ -193,6 +198,8 @@ public class ImageAnalyzer {
targetWorkers[i] = new TargetImageAnalyzerWorker(this, this.targetWorkerName+Integer.toString(i), currWork, currWork+workload); targetWorkers[i] = new TargetImageAnalyzerWorker(this, this.targetWorkerName+Integer.toString(i), currWork, currWork+workload);
currWork += workload; currWork += workload;
} }
targetWorkers[targetWorkersLimit] = new TargetImageAnalyzerWorker(this, this.targetWorkerName+Integer.toString(targetWorkersLimit), currWork, currWork+workload);
Log.log(LogLevel.Debug, "Ended on assigning "+(currWork+workload)+" slot(s)!");
Log.log(LogLevel.Info, "Spawned "+(currWorker+1)+" target worker(s)"); Log.log(LogLevel.Info, "Spawned "+(currWorker+1)+" target worker(s)");
} }
@ -202,10 +209,11 @@ public class ImageAnalyzer {
* (invoked by target worker instances to deliver finished workloads) * (invoked by target worker instances to deliver finished workloads)
* @param clFragment HashMap with classifications and coordinates (slot) as key. * @param clFragment HashMap with classifications and coordinates (slot) as key.
*/ */
public synchronized void addSlotClassifications(HashMap<int[], Integer> clFragment){ public synchronized void addSlotClassifications(HashMap<int[], Integer> clFragment, String workerName){
for(int[] key: clFragment.keySet()){ for(int[] key: clFragment.keySet()){
if(!slotClassifications.containsKey(ImageUtils.parseCoord(key))){ if(!slotClassifications.containsKey(ImageUtils.parseCoord(key))){
this.slotClassifications.put(ImageUtils.parseCoord(key), clFragment.get(key)); this.slotClassifications.put(ImageUtils.parseCoord(key), clFragment.get(key));
Log.log(LogLevel.Debug, "Got a classification added by "+workerName+" "+key[0]+" "+key[1]);
/*if(key[0] == 199 && key[1] == 0){ /*if(key[0] == 199 && key[1] == 0){
Log.log(LogLevel.Error, "ImageAnalyzer.addSlotClassifications() - key[0]==30 && key[1]==0"); Log.log(LogLevel.Error, "ImageAnalyzer.addSlotClassifications() - key[0]==30 && key[1]==0");
Log.log(LogLevel.Error, "Brrrriiiing!"); Log.log(LogLevel.Error, "Brrrriiiing!");
@ -215,6 +223,7 @@ public class ImageAnalyzer {
Log.log(LogLevel.Error, ""); Log.log(LogLevel.Error, "");
}*/ }*/
}else{ }else{
Log.log(LogLevel.Error, "Caused by ["+workerName+"] with "+key[0]+" "+key[1]);
Log.log(LogLevel.Error, "Multiple classifcation of target slot detected! Workloads were not sliced correctly or coordinates are screwed up!"); Log.log(LogLevel.Error, "Multiple classifcation of target slot detected! Workloads were not sliced correctly or coordinates are screwed up!");
continue; continue;
} }
@ -347,12 +356,27 @@ public class ImageAnalyzer {
* @param canvas * @param canvas
* @return * @return
*/ */
public synchronized void placeImage(int gridX, int gridY, BufferedImage input){ public synchronized void placeImage(int gridX, int gridY, BufferedImage input, boolean keepRatio){
assert(gridX < slotX && gridY < slotY); assert(gridX < slotX && gridY < slotY);
assert(input.getWidth() < postSlotWidth && input.getHeight() < postSlotHeight); assert(input.getWidth() < postSlotWidth && input.getHeight() < postSlotHeight);
int picWidth, picHeight;
if(keepRatio){
picWidth = input.getWidth();
picHeight = input.getHeight();
}else{
picWidth = postSlotWidth;
picHeight = postSlotHeight;
}
Graphics2D g2 = (Graphics2D)canvas.getGraphics(); Graphics2D g2 = (Graphics2D)canvas.getGraphics();
g2.drawImage(input, gridX*postSlotWidth, gridY*postSlotHeight, postSlotWidth, postSlotHeight, null); g2.drawImage(input, gridX*postSlotWidth, gridY*postSlotHeight, input.getWidth(), input.getHeight(), null);
if(gridEnd[0] < gridX*postSlotWidth+postSlotWidth){
gridEnd[0] = gridX*postSlotWidth+postSlotWidth;
}
if(gridEnd[1] < gridY*postSlotHeight+postSlotHeight){
gridEnd[1] = gridY*postSlotHeight+postSlotHeight;
}
g2.dispose(); g2.dispose();
//Log.log(LogLevel.Error, "Drawn picture at "+gridX*postSlotWidth+" "+gridY*postSlotHeight+" with "+input.getWidth()+"x"+input.getHeight()); //Log.log(LogLevel.Error, "Drawn picture at "+gridX*postSlotWidth+" "+gridY*postSlotHeight+" with "+input.getWidth()+"x"+input.getHeight());
} }

@ -19,8 +19,8 @@ public class ImageUtils {
g2.dispose(); g2.dispose();
return img; return img;
} }
if(targetSize.getWidth() > targetSize.getHeight()){ if(input.getWidth() > input.getHeight()){
tmp = input.getScaledInstance(-1, (int)targetSize.getHeight(), Image.SCALE_SMOOTH); tmp = input.getScaledInstance((int)targetSize.getWidth(), -1, Image.SCALE_SMOOTH);
img = new BufferedImage(tmp.getWidth(null), tmp.getHeight(null), BufferedImage.TYPE_INT_ARGB); img = new BufferedImage(tmp.getWidth(null), tmp.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) img.getGraphics(); Graphics2D g2 = (Graphics2D) img.getGraphics();
@ -28,7 +28,7 @@ public class ImageUtils {
g2.dispose(); g2.dispose();
return img; return img;
}else{ }else{
tmp = input.getScaledInstance((int)targetSize.getWidth(), -1, Image.SCALE_SMOOTH); tmp = input.getScaledInstance(-1, (int)targetSize.getHeight(), Image.SCALE_SMOOTH);
img = new BufferedImage(tmp.getWidth(null), tmp.getHeight(null), BufferedImage.TYPE_INT_ARGB); img = new BufferedImage(tmp.getWidth(null), tmp.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) img.getGraphics(); Graphics2D g2 = (Graphics2D) img.getGraphics();
@ -38,6 +38,19 @@ public class ImageUtils {
} }
} }
/**
* Converts the given number into the slot coordinates (not pixel coordinates).
* @param ia
* @param num
* @return
*/
public static int[] getSlotCoord(ImageAnalyzer ia, int num){
int[] coords = new int[2];
coords[0] = num%(ia.slotX+1);
coords[1] = num/(ia.slotX+1);
return coords;
}
/** /**
* Converts from a numbered Slot to a specific slot start coordinate. * Converts from a numbered Slot to a specific slot start coordinate.
* *
@ -45,7 +58,16 @@ public class ImageUtils {
* @param preMagnification true if slot sizes before the magnification are to be used. * @param preMagnification true if slot sizes before the magnification are to be used.
* @return * @return
*/ */
public static int[] getSlotCoord(ImageAnalyzer ia, int num, boolean preMagnification){ public static int[] getSlotCoordPixels(ImageAnalyzer ia, int[] coords, boolean preMagnification){
//TODO BUGGGSSS
/*
* Error collision values (num1 num2 preSlotDimensions -> result):
* 18614 18855 7x3 -> 399x174
* 18565 18806 7x3 -> 56x174
* 6735 6976 7x3 -> 1596x63
* 5833 6074 7x3 -> 343x54
* 382 623 7x3 -> 987x3
*/
int slotWidth, slotHeight; int slotWidth, slotHeight;
if(preMagnification){ if(preMagnification){
slotWidth = ia.preSlotWidth; slotWidth = ia.preSlotWidth;
@ -56,10 +78,8 @@ public class ImageUtils {
} }
//TODO -----> FIX überschlag von Zeile 0 in 1; x zählt zu viel! //TODO -----> FIX überschlag von Zeile 0 in 1; x zählt zu viel!
int ySlots = num/(ia.slotY-1); int[] pixelCoords = {coords[0]*slotWidth, coords[1]*slotHeight};
int xSlots = num%(ia.slotX-1); return pixelCoords;
int[] coords = {xSlots*slotWidth, ySlots*slotHeight};
return coords;
} }
public static String parseCoord(int[] coord){ public static String parseCoord(int[] coord){

@ -47,10 +47,10 @@ public class MatchWorker extends ImageAnalyzerWorker{
continue; continue;
} }
if(index == null || slotClassifications.get(ImageUtils.parseCoord(coord)) == null){ //TODO remove if(index == null || slotClassifications.get(ImageUtils.parseCoord(coord)) == null){ //TODO remove
Log.log(LogLevel.Error, "MatchWorker run() -> slotClass.get(ImageUtils.parse(coord)==null"); Log.log(LogLevel.Error, "MatchWorker run() -> slotClassifications.get(ImageUtils.parseCoord(coord)==null");
Log.log(LogLevel.Error, "BRrrring"+slotClassifications.get(ImageUtils.parseCoord(coord))); Log.log(LogLevel.Error, "BRrrring"+slotClassifications.get(ImageUtils.parseCoord(coord)));
Log.log(LogLevel.Error, "parsed: "+ImageUtils.parseCoord(coord)); Log.log(LogLevel.Error, "parsed: "+ImageUtils.parseCoord(coord));
Log.log(LogLevel.Error, ""+coord[0]+" "+coord[1]); Log.log(LogLevel.Error, "Unparsed: "+coord[0]+" "+coord[1]);
Log.log(LogLevel.Error, ""); Log.log(LogLevel.Error, "");
for(String key: slotClassifications.keySet()){ for(String key: slotClassifications.keySet()){
//Log.log(LogLevel.Error, key); //Log.log(LogLevel.Error, key);

@ -1,5 +1,6 @@
package peery.picture.worker; package peery.picture.worker;
import java.awt.Dimension;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -8,6 +9,7 @@ import java.util.HashMap;
import peery.log.Log; import peery.log.Log;
import peery.log.LogLevel; import peery.log.LogLevel;
import peery.picture.ImageAnalyzer; import peery.picture.ImageAnalyzer;
import peery.picture.ImageUtils;
public class PlacementWorker extends ImageAnalyzerWorker{ public class PlacementWorker extends ImageAnalyzerWorker{
@ -29,11 +31,13 @@ public class PlacementWorker extends ImageAnalyzerWorker{
} }
BufferedImage img = ia.fh.loadImage(file); BufferedImage img = ia.fh.loadImage(file);
ArrayList<int[]> coords = coordMap.get(file); ArrayList<int[]> coords = coordMap.get(file);
img = ImageUtils.resizeImage(img, new Dimension(ia.postSlotWidth, ia.postSlotHeight), ia.keepRatio);
Log.log(LogLevel.Debug, "["+this.getName()+"] Resized image "+file.getName()+" to "+img.getWidth()+"x"+img.getHeight()+" !");
Log.log(LogLevel.Info, "["+this.getName()+"] Going to place "+file.getName()+" "+coords.size()+" time(s)!"); Log.log(LogLevel.Info, "["+this.getName()+"] Going to place \""+file.getName()+"\" "+coords.size()+" time(s)!");
int count = 0; int count = 0;
for(int[] coord: coords){ for(int[] coord: coords){
ia.placeImage(coord[0], coord[1], img); ia.placeImage(coord[0], coord[1], img, ia.keepRatio);
if(count % 100 == 0){ if(count % 100 == 0){
Log.log(LogLevel.Info, "["+this.getName()+"] Placed "+count+"/"+coords.size()+" instances! Continuing ..."); Log.log(LogLevel.Info, "["+this.getName()+"] Placed "+count+"/"+coords.size()+" instances! Continuing ...");
} }

@ -37,7 +37,7 @@ public class TargetImageAnalyzerWorker extends ImageAnalyzerWorker{
public void run(){ public void run(){
Log.log(LogLevel.Info, "Worker "+this.getName()+" up and running! Let's roll ..."); Log.log(LogLevel.Info, "Worker "+this.getName()+" up and running! Let's roll ...");
HashMap<int[], Integer> result = this.classifyArea(startCoord, endCoord); HashMap<int[], Integer> result = this.classifyArea(startCoord, endCoord);
ia.addSlotClassifications(result); ia.addSlotClassifications(result, this.getName());
Log.log(LogLevel.Info, "Worker "+this.getName()+" finished work! Terminating ..."); Log.log(LogLevel.Info, "Worker "+this.getName()+" finished work! Terminating ...");
} }
@ -53,9 +53,9 @@ public class TargetImageAnalyzerWorker extends ImageAnalyzerWorker{
public HashMap<int[], Integer> classifyArea(int startCoord, int endCoord){ public HashMap<int[], Integer> classifyArea(int startCoord, int endCoord){
BufferedImage target = ia.target; BufferedImage target = ia.target;
HashMap<int[], Integer> results = new HashMap<int[], Integer>(); HashMap<int[], Integer> results = new HashMap<int[], Integer>();
System.out.println("Was ordered: "+startCoord+" "+endCoord); Log.log(LogLevel.Debug, "["+this.getName()+"] Was ordered to classify "+startCoord+" "+endCoord);
for(int i = startCoord; i < endCoord; i++){ for(int i = startCoord; i < endCoord; i++){
int[] coordPixels = ImageUtils.getSlotCoord(ia, i, true); int[] coordPixels = ImageUtils.getSlotCoordPixels(ia, ImageUtils.getSlotCoord(ia, i), true);
if(coordPixels[0]+ia.preSlotWidth >= ia.target.getWidth() || coordPixels[1]+ia.preSlotHeight >= ia.target.getHeight()){ if(coordPixels[0]+ia.preSlotWidth >= ia.target.getWidth() || coordPixels[1]+ia.preSlotHeight >= ia.target.getHeight()){
//Dirty FIX //Dirty FIX
//This will inevitably land outside the Raster otherwise. I should prevent these Coords from the start //This will inevitably land outside the Raster otherwise. I should prevent these Coords from the start
@ -64,7 +64,9 @@ public class TargetImageAnalyzerWorker extends ImageAnalyzerWorker{
} }
int rgb = classifySlot(coordPixels[0], coordPixels[1], ia.preSlotWidth, ia.preSlotHeight, ia.target); int rgb = classifySlot(coordPixels[0], coordPixels[1], ia.preSlotWidth, ia.preSlotHeight, ia.target);
int[] coordSlot = {coordPixels[0]/ia.preSlotWidth, coordPixels[1]/ia.preSlotHeight}; int[] coordSlot = {coordPixels[0]/ia.preSlotWidth, coordPixels[1]/ia.preSlotHeight};
Log.log(LogLevel.Debug, "["+this.getName()+"] Classified on slot "+coordSlot[0]+" "+coordSlot[1]+" i:"+i
+" coordPixels:"+coordPixels[0]+"x"+coordPixels[1]+" preslotDimensions:"+ia.preSlotWidth+"x"+ia.preSlotHeight+
" slotX:"+ia.slotX+" slotY:"+ia.slotY);
/*if(coordPixels[0] == 210 && coordPixels[1] == 0){//TODO remove /*if(coordPixels[0] == 210 && coordPixels[1] == 0){//TODO remove
System.out.println("Brrrring!"); System.out.println("Brrrring!");
Log.log(LogLevel.Error, "Brrrriiing"+rgb+" "); Log.log(LogLevel.Error, "Brrrriiing"+rgb+" ");
@ -87,8 +89,7 @@ public class TargetImageAnalyzerWorker extends ImageAnalyzerWorker{
* @return average Color as RGB value * @return average Color as RGB value
*/ */
public int classifySlot(int gridX, int gridY, int slotWidth, int slotHeight, BufferedImage target){ public int classifySlot(int gridX, int gridY, int slotWidth, int slotHeight, BufferedImage target){
System.out.println(gridX+" "+gridY+" "+slotWidth+" "+slotHeight); Log.log(LogLevel.Debug, "["+this.getName()+"] Slicing slot at pixels: "+gridX+"x"+gridY+" out of the target with "+slotWidth+"x"+slotHeight+"for classification ...");
Log.log(LogLevel.Debug, "["+this.getName()+"] Slicing slot "+gridX+"x"+gridY+" out of the target for classification ...");
BufferedImage subImage = target.getSubimage(gridX, gridY, slotWidth, slotHeight); BufferedImage subImage = target.getSubimage(gridX, gridY, slotWidth, slotHeight);
ColorModel cm = ColorModel.getRGBdefault(); ColorModel cm = ColorModel.getRGBdefault();
float red = 0, green = 0, blue = 0; float red = 0, green = 0, blue = 0;
@ -106,7 +107,7 @@ public class TargetImageAnalyzerWorker extends ImageAnalyzerWorker{
green = green/pixels; green = green/pixels;
blue = blue/pixels; blue = blue/pixels;
int rgb = new Color((int)red, (int)green, (int)blue).getRGB(); int rgb = new Color((int)red, (int)green, (int)blue).getRGB();
Log.log(LogLevel.Debug, "["+this.getName()+"] Classified slot "+gridX+"x"+gridY+" with following rgb result: value:"+rgb+ Log.log(LogLevel.Debug, "["+this.getName()+"] Classified slot at pixels: "+gridX+"x"+gridY+" with following rgb result: value:"+rgb+
" red:"+red+", green:"+green+", blue:"+blue); " red:"+red+", green:"+green+", blue:"+blue);
return rgb; return rgb;
} }

Loading…
Cancel
Save