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 static final String programmName = "Mosaic",
versionString = "Alpha-0.32";
versionString = "Alpha-0.33";
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,
adaptionCount = 300,
inputWorkerLimit = 10,
@ -21,14 +21,14 @@ public class Mosaic extends Thread{
matchWorkerLimit = 10,
placeWorkerLimit = 2;
private static final double adaptionStep = 1.1, gridErrorThresh = 0.15;
private static boolean keepRatio = false;
/*
*
* Performance:
*
*
* FIX:
* somewhere I'm loosing pixels from the target (the output is cut off as if it was smaller)
* investigate picture stretching -> is ImageUtils.resizeImage() even used?
* rasterization doesn't cover everything!
* alphaThreshhold is currently dead
*
* Feature:
@ -42,7 +42,8 @@ public class Mosaic extends Thread{
public Mosaic(){
fh = new FileHandler("resources");
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();
}
@ -81,6 +82,7 @@ public class Mosaic extends Thread{
e.printStackTrace();
}
}
cutOutGrid();
Log.log.perfLog("Finished Placement!");
Log.log(LogLevel.Info, "Finished placement. Output is done ...");
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.
*/
public void prepMatching(){
ia.updateIndex();
ia.rasterizeTarget(gridX, gridY, targetMulti, gridErrorThresh, adaptionCount, adaptionStep);
ia.updateIndex();
ia.classifyTarget();
}
@ -110,6 +112,12 @@ public class Mosaic extends Thread{
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){
new Mosaic();
}

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

@ -29,6 +29,8 @@ public class ImageAnalyzer {
private HashMap<String, Integer> index;
private int alphaThreshhold;
public final boolean keepRatio;
public int[] gridEnd;
//Input Classification Worker
private int inputWorkersLimit;
@ -57,10 +59,12 @@ public class ImageAnalyzer {
//
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.target = fh.loadImage(fh.TargetImageFile);
this.alphaThreshhold = alphaThreshhold;
this.keepRatio = keepRatio;
this.gridEnd = new int[2];
this.inputWorkersLimit = inputWorkersLimit;
this.targetWorkersLimit = targetWorkersLimit;
@ -179,8 +183,9 @@ public class ImageAnalyzer {
*/
public void classifyTarget(){
Log.log(LogLevel.Info, "Starting Target Classification. Calculating workload and spawning worker(s) ...");
this.targetWorkers = new TargetImageAnalyzerWorker[targetWorkersLimit];
int workload = this.slotCount / this.targetWorkersLimit;
this.targetWorkers = new TargetImageAnalyzerWorker[targetWorkersLimit+1];
Log.log(LogLevel.Debug, slotCount+" slot(s) need to be classified!");
int workload = this.slotCount / (this.targetWorkersLimit);
int initialWork = this.slotCount % workload;
int currWorker = 0;
if(initialWork != 0){
@ -193,6 +198,8 @@ public class ImageAnalyzer {
targetWorkers[i] = new TargetImageAnalyzerWorker(this, this.targetWorkerName+Integer.toString(i), currWork, 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)");
}
@ -202,10 +209,11 @@ public class ImageAnalyzer {
* (invoked by target worker instances to deliver finished workloads)
* @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()){
if(!slotClassifications.containsKey(ImageUtils.parseCoord(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){
Log.log(LogLevel.Error, "ImageAnalyzer.addSlotClassifications() - key[0]==30 && key[1]==0");
Log.log(LogLevel.Error, "Brrrriiiing!");
@ -215,6 +223,7 @@ public class ImageAnalyzer {
Log.log(LogLevel.Error, "");
}*/
}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!");
continue;
}
@ -347,12 +356,27 @@ public class ImageAnalyzer {
* @param canvas
* @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(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();
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();
//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();
return img;
}
if(targetSize.getWidth() > targetSize.getHeight()){
tmp = input.getScaledInstance(-1, (int)targetSize.getHeight(), Image.SCALE_SMOOTH);
if(input.getWidth() > input.getHeight()){
tmp = input.getScaledInstance((int)targetSize.getWidth(), -1, Image.SCALE_SMOOTH);
img = new BufferedImage(tmp.getWidth(null), tmp.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) img.getGraphics();
@ -28,7 +28,7 @@ public class ImageUtils {
g2.dispose();
return img;
}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);
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.
*
@ -45,7 +58,16 @@ public class ImageUtils {
* @param preMagnification true if slot sizes before the magnification are to be used.
* @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;
if(preMagnification){
slotWidth = ia.preSlotWidth;
@ -56,10 +78,8 @@ public class ImageUtils {
}
//TODO -----> FIX überschlag von Zeile 0 in 1; x zählt zu viel!
int ySlots = num/(ia.slotY-1);
int xSlots = num%(ia.slotX-1);
int[] coords = {xSlots*slotWidth, ySlots*slotHeight};
return coords;
int[] pixelCoords = {coords[0]*slotWidth, coords[1]*slotHeight};
return pixelCoords;
}
public static String parseCoord(int[] coord){

@ -47,10 +47,10 @@ public class MatchWorker extends ImageAnalyzerWorker{
continue;
}
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, "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, "");
for(String key: slotClassifications.keySet()){
//Log.log(LogLevel.Error, key);

@ -1,5 +1,6 @@
package peery.picture.worker;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
@ -8,6 +9,7 @@ import java.util.HashMap;
import peery.log.Log;
import peery.log.LogLevel;
import peery.picture.ImageAnalyzer;
import peery.picture.ImageUtils;
public class PlacementWorker extends ImageAnalyzerWorker{
@ -29,11 +31,13 @@ public class PlacementWorker extends ImageAnalyzerWorker{
}
BufferedImage img = ia.fh.loadImage(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;
for(int[] coord: coords){
ia.placeImage(coord[0], coord[1], img);
ia.placeImage(coord[0], coord[1], img, ia.keepRatio);
if(count % 100 == 0){
Log.log(LogLevel.Info, "["+this.getName()+"] Placed "+count+"/"+coords.size()+" instances! Continuing ...");
}

@ -37,7 +37,7 @@ public class TargetImageAnalyzerWorker extends ImageAnalyzerWorker{
public void run(){
Log.log(LogLevel.Info, "Worker "+this.getName()+" up and running! Let's roll ...");
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 ...");
}
@ -53,9 +53,9 @@ public class TargetImageAnalyzerWorker extends ImageAnalyzerWorker{
public HashMap<int[], Integer> classifyArea(int startCoord, int endCoord){
BufferedImage target = ia.target;
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++){
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()){
//Dirty FIX
//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[] 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
System.out.println("Brrrring!");
Log.log(LogLevel.Error, "Brrrriiing"+rgb+" ");
@ -87,8 +89,7 @@ public class TargetImageAnalyzerWorker extends ImageAnalyzerWorker{
* @return average Color as RGB value
*/
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 "+gridX+"x"+gridY+" out of the target for classification ...");
Log.log(LogLevel.Debug, "["+this.getName()+"] Slicing slot at pixels: "+gridX+"x"+gridY+" out of the target with "+slotWidth+"x"+slotHeight+"for classification ...");
BufferedImage subImage = target.getSubimage(gridX, gridY, slotWidth, slotHeight);
ColorModel cm = ColorModel.getRGBdefault();
float red = 0, green = 0, blue = 0;
@ -106,7 +107,7 @@ public class TargetImageAnalyzerWorker extends ImageAnalyzerWorker{
green = green/pixels;
blue = blue/pixels;
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);
return rgb;
}

Loading…
Cancel
Save