diff --git a/src/peery/Mosaic.java b/src/peery/Mosaic.java new file mode 100644 index 0000000..76c6dfe --- /dev/null +++ b/src/peery/Mosaic.java @@ -0,0 +1,122 @@ +package peery; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; + +import peery.file.FileHandler; +import peery.log.Log; +import peery.log.LogLevel; +import peery.picture.ImageAnalyzer; + +public class Mosaic { + + public static final String versionString = "Alpha-0.1"; + + private static final String outputName = "Output"; + private static final int gridX = 100, gridY = 100, targetMulti = 4, + alphaThreshhold = 30, + adaptionCount = 300; + private static final double adaptionStep = 1.1, gridErrorThresh = 0.15; + /* + * + * TODO improve performance during closest match search. -> Loads ALOT of images + * TODO investigate picture stretching -> is ImageUtils.resizeImage() even used? + * TODO investigate why so few slots are actually present, I specified way more! <--- + * + * + * TODO alphaThreshhold is currently dead + */ + + public FileHandler fh; + public ImageAnalyzer ia; + + public Mosaic(){ + fh = new FileHandler("resources"); + Log.log(LogLevel.Info, "Starting Mosaic "+versionString); + ia = new ImageAnalyzer(fh); + createMosaic(); + } + + public void createMosaic(){ + ia.rasterizeTarget(gridX, gridY, targetMulti, gridErrorThresh, adaptionCount, adaptionStep); + HashMap index = fh.loadIndex(); + + //Loading index + if(index == null){ + Log.log(LogLevel.Info, "No index loaded. Working with empty one ..."); + index = new HashMap(); + } + // + //Preparing Setup + ArrayList fileList = fh.listInputFiles(); + + Log.log(LogLevel.Info, "Starting classification of Input now ..."); + int count = 0; + for(String path: fileList){ + Log.log(LogLevel.Info, "Processing file "+(count++)+"/"+fileList.size()+" ..."); + File file = new File(path); + BufferedImage img = fh.loadImage(file); + if(img == null){ + continue; + } + int rgb = ia.classifyImage(img, file, alphaThreshhold); + fh.appendToIndex(index, file, rgb); + } + Log.log(LogLevel.Info, "Finished classification. Index is ready for production. Reloading index ..."); + index = fh.loadIndex(); + + Log.log(LogLevel.Debug, "Canvas is "+ia.canvas.getWidth()+"x"+ia.canvas.getHeight()+" big."); + Log.log(LogLevel.Debug, "Grid will span "+ia.slotWidth*gridX+"x"+ia.slotHeight*gridY+" ."); + Log.log(LogLevel.Info, "Starting classification of target slots."); + count = 0; + int maxSlot = ia.slotX*ia.slotY; + int[][] slotRGBs = new int[ia.slotX][ia.slotY]; + for(int x = 0; x < ia.slotX; x++){ + for(int y = 0; y < ia.slotY; y++){ + Log.log(LogLevel.Info, "Processing slot "+(count++)+"/"+maxSlot+" ..."); + slotRGBs[x][y] = ia.classifySlot(x, y, ia.target); + } + } + Log.log(LogLevel.Info, "Finished classification of target slots."); + + Log.log(LogLevel.Info, "Matching indexed Images on slots ..."); + count = 0; + ArrayList fileHolder = new ArrayList(); + ArrayList imgHolder = new ArrayList(); + for(int x = 0; x < slotRGBs.length; x++){ + for(int y = 0; y < slotRGBs[x].length; y++){ + Log.log(LogLevel.Info, "Matching slot "+(count++)+"/"+maxSlot+" ..."); + HashMap matches = ia.matchClosestIndex(index, slotRGBs[x][y], 0); + String match = matches.keySet().toArray()[0].toString(); + File file = new File(fh.InputImagesFolder+fh.fs+match); + + /* + BufferedImage plain = new BufferedImage(ia.slotWidth, ia.slotHeight, BufferedImage.TYPE_INT_RGB); + Graphics2D g2 = (Graphics2D) plain.getGraphics(); + g2.setColor(new Color(slotRGBs[x][y])); + g2.fillRect(0, 0, plain.getWidth(), plain.getHeight()); + g2.dispose(); + ia.placeImage(x, y, plain); + */ + BufferedImage img; + if(!fileHolder.contains(file)){ + fileHolder.add(file); + img = fh.loadImage(file); + imgHolder.add(img); + }else{ + int i = fileHolder.indexOf(file); + img = imgHolder.get(i); + } + ia.placeImage(x, y, img); + } + } + Log.log(LogLevel.Info, "Finished matching. Output is done ..."); + fh.saveImage(ia.canvas, new File(fh.OutputFolder+fh.fs+outputName+"-"+fh.OutputFolder.listFiles().length+".png")); + } + + public static void main(String[] args){ + new Mosaic(); + } +} diff --git a/src/peery/file/FileHandler.java b/src/peery/file/FileHandler.java index a3bc4be..d303583 100644 --- a/src/peery/file/FileHandler.java +++ b/src/peery/file/FileHandler.java @@ -2,9 +2,16 @@ package peery.file; import java.awt.Dimension; import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Scanner; import javax.imageio.ImageIO; @@ -13,33 +20,52 @@ import peery.log.LogLevel; public class FileHandler { - public File sourceFolder, InputImagesFolder, TargetImageFile, OutputFolder; + public File sourceFolder, InputImagesFolder, TargetImageFile, OutputFolder, indexFile; /* * sourcePath/ -> all ressources * sourcePath/Images/ -> Input pictures folder * sourcePath/Target -> Target picture file * sourcePath/Output/ -> Output picture folder */ + public final String fs; public FileHandler(String sourcePath){ + if(!System.getProperty("os.name").startsWith("Windows")){ + fs = "/"; + }else{ + fs = "\\"; + } this.sourceFolder = new File(sourcePath); - this.InputImagesFolder = new File(sourceFolder.getAbsolutePath()+"/Images"); - this.TargetImageFile = new File(sourceFolder.getAbsolutePath()+"/Target"); - this.OutputFolder = new File(sourceFolder.getAbsolutePath()+"/Output"); + this.InputImagesFolder = new File(sourceFolder.getAbsolutePath()+fs+"Images"); + this.TargetImageFile = new File(sourceFolder.getAbsolutePath()+fs+"Target"); + this.OutputFolder = new File(sourceFolder.getAbsolutePath()+fs+"Output"); + this.indexFile = new File(this.InputImagesFolder.getAbsolutePath()+"Index.txt"); Log.initLog(this.sourceFolder.getAbsolutePath()); + if(fs == "\\"){ + Log.log(LogLevel.Debug, "Assumed Windows like Folder declaration. Therefore using "+fs+" as a separator."); + }else{ + Log.log(LogLevel.Debug, "Detected Linux or OSX."); + } this.validateFolderStructure(); } public boolean validateFolderStructure(){ if(this.sourceFolder.isDirectory()){ - Log.log(LogLevel.Debug, "Detected sourcefolder at "+this.sourceFolder.getAbsolutePath()); + Log.log(LogLevel.Debug, "Detected source folder at "+this.sourceFolder.getAbsolutePath()); if(this.InputImagesFolder.isDirectory()){ Log.log(LogLevel.Debug, "Detected Input folder at "+this.InputImagesFolder.getAbsolutePath()); if(this.OutputFolder.isDirectory()){ Log.log(LogLevel.Debug, "Detected Output folder at "+this.OutputFolder.getAbsolutePath()); if(this.TargetImageFile.isFile()){ Log.log(LogLevel.Debug, "Detected Target Image at "+this.TargetImageFile.getAbsolutePath()); - return true; + if(!this.indexFile.isDirectory()){ + Log.log(LogLevel.Debug, "Found no directory blocking the index file."); + return true; + } + else{ + Log.log(LogLevel.Error, "Following folder collides with the index file name: "+this.indexFile.getAbsolutePath()); + System.exit(1); + } }else{ Log.log(LogLevel.Critical, "No Target Image found! Exiting..."); System.exit(1); @@ -64,11 +90,24 @@ public class FileHandler { return false; } + public ArrayList listInputFiles(){ + Log.log(LogLevel.Info, "Listing files inside "+this.InputImagesFolder.getName()+" ..."); + ArrayList fileList = new ArrayList(); + for(File f: this.InputImagesFolder.listFiles()){ + if(f.isFile()){ + fileList.add(f.getAbsolutePath()); + } + } + return fileList; + } + public BufferedImage loadImage(File file){ + Log.log(LogLevel.Info, "Loading image "+file.getName()+" ..."); if(file.isFile() && file.canRead()){ BufferedImage img; try { img = ImageIO.read(file); + Log.log(LogLevel.Debug, "Loaded image "+file.getName()+" !"); return img; } catch (IOException e) { Log.log(LogLevel.Debug, "File "+file.getPath()+" failed to load as an Image. What did I just read?"); @@ -82,6 +121,96 @@ public class FileHandler { } } + public void saveImage(BufferedImage img, File file){ + Log.log(LogLevel.Info, "Saving image as file "+file.getAbsolutePath()); + try { + ImageIO.write(img, "png", file); + } catch (IOException e) { + Log.log(LogLevel.Critical, "Couldn't write image "+file.getName()+" to file! Are write permissions missing?" + + " Attempted to write at "+file.getAbsolutePath()); + e.printStackTrace(); + } + } + + public void appendToIndex(HashMap index, File file, int rgb){ + try { + Log.log(LogLevel.Debug, "Checking index entries for "+file.getName()); + if(!indexFile.createNewFile() && loadIndexEntry(index, file) != null){ + Log.log(LogLevel.Debug, "An Entry seems to already exist for "+file.getName()); + return; + } + BufferedWriter bw = new BufferedWriter(new FileWriter(indexFile, true)); + bw.write(rgb+";"+file.getName()+"\n"); + bw.flush(); + bw.close(); + Log.log(LogLevel.Info, "Wrote index entry for "+file.getName()+" !"); + } catch (IOException e) { + Log.log(LogLevel.Critical, "Couldn't create or write index file "+indexFile.getAbsolutePath()+" ." + + "Are write permissions missing?"); + e.printStackTrace(); + return; + } + } + + /** + * Loads an index entry for a single file. + * + * Loads and parses the whole index in the background if not given the indexData. + * @param indexData + * @param file + * @return + */ + public Integer loadIndexEntry(HashMap indexData, File file){ + Log.log(LogLevel.Debug, "Searching for index data of "+file.getName()+" ..."); + if(indexData == null){ + indexData = loadIndex(); + } + return indexData.get(file.getName()); + } + + /** + * Loads the whole index file into a Hashmap. + * The second value (file name) is used as a String-key, the rgb value is the int-value. + * @param file + * @return + */ + public HashMap loadIndex(){ + if(!this.indexFile.exists()){ + Log.log(LogLevel.Info, "No Index file found. Nothing to load then..."); + return null; + } + HashMap indexData = new HashMap(); + try { + Scanner sc = new Scanner(new BufferedReader(new FileReader(this.indexFile))); + while(sc.hasNext()){ + @SuppressWarnings("rawtypes") + ArrayList data = parseIndexData(sc.nextLine()); + indexData.put((String)data.get(1), (int)data.get(0)); + } + sc.close(); + } catch (FileNotFoundException e) { + Log.log(LogLevel.Critical, "Could not open index file! Do I have read permissions?"); + e.printStackTrace(); + } + return indexData; + } + + /** + * Parses a line of indexData into an ArrayList containing the rgb int and the name + * @param indexData + * @return + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + private ArrayList parseIndexData(String indexData){ + String[] data = indexData.split(";"); + ArrayList result = new ArrayList(); + result.add(Integer.parseInt(data[0])); + result.add(data[1]); + + return result; + } + + // could use a single image variant to check synchronized to the classification (saves IO) public Dimension loadBiggestDimension(){ File[] files = this.InputImagesFolder.listFiles(); int width = 0, height = 0, img_count = 0; diff --git a/src/peery/log/Log.java b/src/peery/log/Log.java index 3e890c5..b3eea0d 100644 --- a/src/peery/log/Log.java +++ b/src/peery/log/Log.java @@ -9,7 +9,7 @@ public class Log { public static Log log; public static final boolean silenceDebug = false, - appendEvents = true, appendErrors = false; + appendEvents = false, appendErrors = false; public final File eventFile, errorFile; private BufferedWriter eventWriter, errorWriter; @@ -42,6 +42,19 @@ public class Log { Log.log = new Log(location); } + public static void shutdownLog(){ + if(Log.log == null){ + return; + } + try { + Log.log.errorWriter.close(); + Log.log.eventWriter.close(); + Log.log = null; + } catch (IOException e) { + e.printStackTrace(); + } + } + public static void log(int logLvl, String message){ Log.log.logs(logLvl, message); } @@ -70,15 +83,17 @@ public class Log { System.out.println(msg); try { logWriter.write(msg+"\n"); - logWriter.flush(); + if(LogLevel.Info.ordinal() < logLvl){ //Saves perfomance? + logWriter.flush(); + } } catch (IOException e) { e.printStackTrace(); } } - + /* public static void main(String[] args){ Log.initLog("/home/peery/Software_Projects/EclipseWorkspace/Picture Mosaic/resources/"); Log.log(LogLevel.Debug, "Test!"); Log.log(LogLevel.Error, "TEST ERROR"); - } + }*/ } diff --git a/src/peery/picture/Classifier.java b/src/peery/picture/Classifier.java deleted file mode 100644 index 721586b..0000000 --- a/src/peery/picture/Classifier.java +++ /dev/null @@ -1,67 +0,0 @@ -package peery.picture; - -import java.awt.Color; -import java.awt.image.BufferedImage; -import java.awt.image.ColorModel; -import java.io.File; - -import peery.file.FileHandler; -import peery.log.Log; -import peery.log.LogLevel; - -public class Classifier { - - public BufferedImage target; - - public Classifier(FileHandler fh){ - BufferedImage target = fh.loadImage(fh.TargetImageFile); - } - - public void rasterizeTarget(){ - - } - - /** - * Plain calculation of average Color of an Image via RGB. - * Takes average of RGB values of each pixel. - * Does not account for alpha. - * @param img Image to process - * @param alphaThreshhold value under which pixels are discarded - * @return RGB value of the average color - */ - public int classifyImage(BufferedImage img, File file, int alphaTreshhold){ - int width = img.getWidth(); - int height = img.getHeight(); - Log.log(LogLevel.Debug, "Starting classification of "+file.getPath()+" with width:"+ - width+" and height:"+height+" ..."); - - ColorModel cm = ColorModel.getRGBdefault(); - float red = 0, green = 0, blue = 0; - int pixels = 0; - for(int x = 0; x < img.getWidth(); x++){ - for(int y = 0; y < img.getHeight(); y++){ - int rgb = img.getRGB(x, y); - red += cm.getRed(rgb); - blue += cm.getBlue(rgb); - green += cm.getGreen(rgb); - pixels++; - } - } - red = red/pixels; - green = green/pixels; - blue = blue/pixels; - int rgb = new Color((int)red, (int)green, (int)blue).getRGB(); - Log.log(LogLevel.Debug, "Classified "+file.getPath()+" with following rgb result: value:"+rgb+ - " red:"+red+", green:"+green+", blue:"+blue); - return rgb; - } - - public static void main(String[] args){ - FileHandler fh = new FileHandler("/home/peery/Software_Projects/EclipseWorkspace/Picture Mosaic/resources"); - BufferedImage[] bfs = fh.loadAllImages(); - Classifier cl = new Classifier(fh); - cl.classifyImage(bfs[0], new File("DEBUG_VALUE"), 30); - System.out.println(fh.loadBiggestDimension()); - } - -} diff --git a/src/peery/picture/ImageAnalyzer.java b/src/peery/picture/ImageAnalyzer.java new file mode 100644 index 0000000..449ed15 --- /dev/null +++ b/src/peery/picture/ImageAnalyzer.java @@ -0,0 +1,238 @@ +package peery.picture; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.io.File; +import java.text.DecimalFormat; +import java.util.HashMap; + +import peery.file.FileHandler; +import peery.log.Log; +import peery.log.LogLevel; + +public class ImageAnalyzer { + + public BufferedImage target; + private FileHandler fh; + + private Dimension /*biggestInputSize,*/ targetSize; + public int slotWidth, slotHeight, slotX, slotY; + public BufferedImage canvas; + + public ImageAnalyzer(FileHandler fh){ + this.fh = fh; + this.target = fh.loadImage(fh.TargetImageFile); + } + + public void rasterizeTarget(int gridX, int gridY, float targetSizeMultiplier, double gridErrorThresh, int adaptionThreshhold, double adaptionStep){ + Log.log(LogLevel.Info, "Rasterizing target image ..."); + Log.log(LogLevel.Info, "Aiming for "+gridX+"*"+gridY+"="+(gridX*gridY)+" tiles ..."); + //this.biggestInputSize = this.fh.loadBiggestDimension(); + this.targetSize = new Dimension(this.target.getWidth(), this.target.getHeight()); + + //TMP + int count = 0; + DecimalFormat df = new DecimalFormat("#"); + while(true){ + double realSlotWidth = ((targetSize.width*targetSizeMultiplier)/gridX); + double realSlotHeight = ((targetSize.height*targetSizeMultiplier)/gridY); + Log.log(LogLevel.Debug, "Perfect slot Size would be "+realSlotWidth+"x"+realSlotHeight); + double widthLoss = Math.abs(realSlotWidth - Double.parseDouble(df.format(realSlotWidth))); + double heightLoss = Math.abs(realSlotHeight - Double.parseDouble(df.format(realSlotHeight))); + if(widthLoss > gridErrorThresh || heightLoss > gridErrorThresh){ + Log.log(LogLevel.Critical, "Grid misplacement error exceeded threshhold! Error is width:"+widthLoss+" height:"+heightLoss); + if(widthLoss > gridErrorThresh){ + gridX *= adaptionStep; + } + if(heightLoss > gridErrorThresh){ + gridY *= adaptionStep; + } + Log.log(LogLevel.Info, "This is the "+(++count)+". adaption to ease the error."); + Log.log(LogLevel.Info, "Aiming for "+gridX+"*"+gridY+"="+(gridX*gridY)+" tiles ..."); + if(count > adaptionThreshhold){ + Log.log(LogLevel.Critical, "Could not adapt to grid misplacement error! The result might be cut off or missing parts!"); + break; + } + continue; + }else{ + break; + } + } + + + slotWidth = (int) ((targetSize.width*targetSizeMultiplier)/gridX); + slotHeight = (int) ((targetSize.height*targetSizeMultiplier)/gridY); + // + + + Log.log(LogLevel.Debug, "Target will be "+(int)(targetSize.width*targetSizeMultiplier) + +"x"+(int)(targetSize.height*targetSizeMultiplier)+" big."); + Log.log(LogLevel.Debug, "Slots are "+slotWidth+"x"+slotHeight+" big."); + slotX = gridX; + slotY = gridY; + //ia.slotWidth*gridX+"x"+ia.slotHeight*gridY + //canvas = new BufferedImage((int)(targetSize.getWidth()*targetSizeMultiplier), (int)(targetSize.getHeight()*targetSizeMultiplier), BufferedImage.TYPE_INT_ARGB); + canvas = new BufferedImage(slotWidth*gridX, slotHeight*gridY, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = (Graphics2D) canvas.getGraphics(); + g2.setColor(Color.BLACK); + g2.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()); + } + + /** + * Compares the given rgb value with the index and returns a HashMap of the closest hits. + * Unlikely to yield more than 1 result without deviationPercentage + * @param index + * @param rgb + * @param deviation How much the matches can be different from the perfect match, and still be taken. + * @return + */ + public HashMap matchClosestIndex(HashMap index, int rgb, int deviation){ + Log.log(LogLevel.Debug, "Searching for closest match for rgb:"+rgb+" in the index with deviation of "+deviation+"."); + assert(deviation < 100 && 0 <= deviation); + if(index == null){ + Log.log(LogLevel.Critical, "No Index was given for rgb matching. Loading it from file ..."); + index = this.fh.loadIndex(); + } + HashMap metrics = new HashMap(); + double currBest = -1; + for(String key: index.keySet()){ + double metric = getMetric(index.get(key), rgb); + metrics.put(key, metric); + if(currBest > metric || currBest == -1){ + currBest = metric; + } + } + Log.log(LogLevel.Info, "Calculated all metrics for rgb:"+rgb+" !"); + + HashMap matches = new HashMap(); + for(String key: metrics.keySet()){ + if(metrics.get(key) == currBest || metrics.get(key) < currBest+(currBest*(deviation/(double)100))){ + matches.put(key, index.get(key)); + } + } + Log.log(LogLevel.Debug, "Grabbed all good matches for rgb:"+rgb+" ! Got "+matches.size()+" ..."); + return matches; + } + + /** + * Calculates the euclidian metric of two given rgb values. + * @param rgb1 + * @param rgb2 + * @return + */ + private double getMetric(int rgb1, int rgb2){ + ColorModel cm = ColorModel.getRGBdefault(); + double result = Math.sqrt(Math.pow((cm.getRed(rgb1)-cm.getRed(rgb2)), 2)+ + Math.pow(cm.getGreen(rgb1)-cm.getGreen(rgb2), 2)+ + Math.pow(cm.getBlue(rgb1)-cm.getBlue(rgb2), 2)); + return result; + } + + /** + * Places the given input in its specified slot (gridX, gridY) on the canvas. + * Assumes and checks boundaries calculated by rasterizeTarget(). + * @param gridX + * @param gridY + * @param input + * @param canvas + * @return + */ + public void placeImage(int gridX, int gridY, BufferedImage input){ + assert(gridX < slotX && gridY < slotY); + assert(input.getWidth() < slotWidth && input.getHeight() < slotHeight); + + Graphics2D g2 = (Graphics2D)canvas.getGraphics(); + g2.drawImage(input, gridX*slotWidth, gridY*slotHeight, slotWidth, slotHeight, null); + g2.dispose(); + } + + /** + * Plain calculation of average Color of an Image via RGB. + * Takes average of RGB values of each pixel. + * Does not account for alpha. + * @param img Image to process + * @param alphaThreshhold value under which pixels are discarded + * @return RGB value of the average color + */ + public int classifyImage(BufferedImage img, File file, int alphaTreshhold){ + int width = img.getWidth(); + int height = img.getHeight(); + Log.log(LogLevel.Debug, "Starting classification of "+file.getName()+" with width:"+ + width+" and height:"+height+" ..."); + + ColorModel cm = ColorModel.getRGBdefault(); + float red = 0, green = 0, blue = 0; + int pixels = 0; + for(int x = 0; x < img.getWidth(); x++){ + for(int y = 0; y < img.getHeight(); y++){ + int rgb = img.getRGB(x, y); + red += cm.getRed(rgb); + blue += cm.getBlue(rgb); + green += cm.getGreen(rgb); + pixels++; + } + } + red = red/pixels; + green = green/pixels; + blue = blue/pixels; + int rgb = new Color((int)red, (int)green, (int)blue).getRGB(); + Log.log(LogLevel.Info, "Classified "+file.getPath()+" with following rgb result: value:"+rgb+ + " red:"+red+", green:"+green+", blue:"+blue); + return rgb; + } + + public int classifySlot(int gridX, int gridY, BufferedImage target){ + int slotWidth = target.getWidth()/slotX, + slotHeight = target.getHeight()/slotY; + BufferedImage subImage = target.getSubimage(gridX*slotWidth, gridY*slotHeight, slotWidth, slotHeight); + Log.log(LogLevel.Debug, "Slicing slot "+gridX+"x"+gridY+" out of the target for classification ..."); + ColorModel cm = ColorModel.getRGBdefault(); + float red = 0, green = 0, blue = 0; + int pixels = 0; + for(int x = 0; x < subImage.getWidth(); x++){ + for(int y = 0; y < subImage.getHeight(); y++){ + int rgb = subImage.getRGB(x, y); + red += cm.getRed(rgb); + green += cm.getGreen(rgb); + blue += cm.getBlue(rgb); + pixels++; + } + } + red = red/pixels; + green = green/pixels; + blue = blue/pixels; + int rgb = new Color((int)red, (int)green, (int)blue).getRGB(); + Log.log(LogLevel.Debug, "Classified slot "+gridX+"x"+gridY+" with following rgb result: value:"+rgb+ + " red:"+red+", green:"+green+", blue:"+blue); + return rgb; + } +/* + public static void main(String[] args){ + System.out.println("ZHE DEBUG"); + /* + FileHandler fh = new FileHandler("/home/peery/Software_Projects/EclipseWorkspace/Picture Mosaic/resources"); + ImageAnalyzer ia = new ImageAnalyzer(fh); + + HashMap index = fh.loadIndex(); + for(File f: fh.InputImagesFolder.listFiles()){ + BufferedImage img = fh.loadImage(f); + if(img == null){ + continue; + } + int indexValue = ia.classifyImage(img, f, 30); + fh.appendToIndex(index, f, indexValue); + } + index = fh.loadIndex(); + System.out.println(index.get("Peery-sketch.png")); + System.out.println(index.get("rasd")); + System.out.println(index.get("Larry the Tiger - Candy Shop Logo (Gift).png")); + System.out.println(ia.matchClosestIndex(index, -10744103, 5)); + //BufferedImage img = ImageUtils.resizeImage(fh.loadImage(fh.InputImagesFolder.listFiles()[0]), new Dimension(500, 300), false); + //fh.saveImage(img, new File("/home/peery/Software_Projects/EclipseWorkspace/Picture Mosaic/resources/resize-test.png")); + + }*/ + +} diff --git a/src/peery/picture/ImageUtils.java b/src/peery/picture/ImageUtils.java new file mode 100644 index 0000000..9174388 --- /dev/null +++ b/src/peery/picture/ImageUtils.java @@ -0,0 +1,41 @@ +package peery.picture; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; + +public class ImageUtils { + + public static BufferedImage resizeImage(BufferedImage input, Dimension targetSize, boolean keepRatio){ + Image tmp; + BufferedImage img; + if(!keepRatio){ + tmp = input.getScaledInstance((int)targetSize.getWidth(), (int)targetSize.getHeight(), Image.SCALE_SMOOTH); + img = new BufferedImage(tmp.getWidth(null), tmp.getHeight(null), BufferedImage.TYPE_INT_ARGB); + + Graphics2D g2 = (Graphics2D) img.getGraphics(); + g2.drawImage(tmp, 0, 0, null); + g2.dispose(); + return img; + } + if(targetSize.getWidth() > targetSize.getHeight()){ + 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(); + g2.drawImage(tmp, 0, 0, null); + g2.dispose(); + return img; + }else{ + 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(); + g2.drawImage(tmp, 0, 0, null); + g2.dispose(); + return img; + } + } + +}