package fr.unistra.pelican.util; /** * * Class containing various static tools.. * * */ public class BasinTools { private double hueA; private double hueB; private double lum; private double sat; /** * * This constructor exists with the sole purpose of making it possible * to compute * */ public BasinTools() { hueA = 0.0; hueB = 0.0; lum = 0.0; sat = 0.0; } public static final double epsilon = 10e-6; /** * simple metric to be used during basin clustering * * the descriptors are assumed to contain: avg luminance, * avg saturation and avg (weighted?) hue. * * @param p1 descriptor of basin1 * @param p2 descriptor of basin2 * @param w component weights * @return */ public static double distance(double[] p1,double[] p2,double[] w) { double esik = 0.11; double dist = 0.0; if(p1.length != p2.length){ System.err.println("basinDistance: Incompatible vector lengths"); return -1.0; } double hueDiff = Tools.hueDistance(p1[0],p2[0]) * 2.0 * w[0]; double satDiff = Math.abs(p1[1] - p2[1]) * w[1]; double lumDiff = Math.abs(p1[2] - p2[2]) * w[2]; double coeff = 1 / ((1 + Math.exp(-10 * (p1[1] - 0.5))) * (1 + Math.exp(-10 * (p2[1] - 0.5)))); // renkozu dist += hueDiff * hueDiff * coeff; //dist += hueDiff * hueDiff; // doygunluk dist += satDiff * satDiff; // aydinlik //dist += lumDiff * lumDiff * (1-coeff); dist += lumDiff * lumDiff; return Math.sqrt(dist); } /** * simple metric to be used during basin clustering * * the descriptors are assumed to contain: avg luminance, * avg saturation and avg (weighted?) hue. * * @param p1 descriptor of basin1 * @param p2 descriptor of basin2 * @param width component weights * @return */ public static double discreteDistance(double[] p1,double[] p2,double esik) { double lumDiff = Math.abs(p1[2]-p2[2]); double satDiff = Math.abs(p1[1]-p2[1]); double hueDiff = hueDiffBoost(Tools.hueDistance(p1[0],p2[0])); /* // once bakalim, renk onemli mi. if (Math.min(p1[1],p2[1]) >= esik){ // renk ozu //return Tools.hueDistance(p1[0],p2[0]) * 2.0 * 0.75 + Math.abs(p1[1] - p2[1]) * 0.25; return Math.sqrt((hueDiff * hueDiff + satDiff * satDiff * 0.5) / 1.5); }else if (Math.max(p1[1],p2[1]) <= esik){ // aydinlik //return Math.abs(p1[2] - p2[2]) * 0.75 + Math.abs(p1[1] - p2[1]) * 0.25; return Math.sqrt(lumDiff * lumDiff); }else{// durum ortada // aydinlik //return Math.abs(p1[2] - p2[2]) * 0.75 + Math.abs(p1[1] - p2[1]) * 0.25; return Math.sqrt((lumDiff * lumDiff + 0.5 * satDiff * satDiff) / 1.5); } */ // \in [5,50] //double slope = -5 - 45 * (1 - esik); double slope = -10; double coeff = 1 / ((1 + Math.exp(slope * (p1[1] - esik))) * (1 + Math.exp(slope * (p2[1] - esik)))); double coeffSat = (Math.exp(2 * satDiff) - 1)/(Math.exp(2 * 1.0) - 1.0); double coeffLum = (Math.exp(2 * lumDiff) - 1)/(Math.exp(2 * 1.0) - 1.0); return ((hueDiff * coeff + lumDiff * (1-coeff)) * (1-coeffSat) + coeffSat * satDiff) * (1-coeffLum) + coeffLum * lumDiff; } // tekrar ele alalim...olagan sartlar altinda, islev : [1/3;0.5] -> [1/3;1.0] // bunun icin de, islevi [0,2/3] arasi tasarlayip kicina 1/3 baglayalim public static double hueDiffBoost(double delta) { //if (delta <= 1/3) return delta; //else return 1/3 + (Math.exp(6 * (delta - 1/3)) - 1)/(Math.exp(1) - 1); if (delta <= 0.25) return Math.exp(4 * delta * Math.log(2)) - 1; else return 1.0; } /** * simple metric to be used during basin clustering with the RGB colour space * * @param p1 descriptor of basin1 * @param p2 descriptor of basin2 * @param width component weights * @return */ public static double RGBMaxDistance(double[] p1,double[] p2) { double red = Math.abs(p1[0] - p2[0]); double green = Math.abs(p1[1] - p2[1]); double blue = Math.abs(p1[2] - p2[2]); //return Math.max(red,Math.max(green,blue)); return Math.sqrt(red * red + green * green + blue * blue) / Math.sqrt(2.0); } /** * basin descriptor sum..see basinDistance * * @param p vector */ public void addUp(double[] p) { // renk ozu..bu asamada sadece ara toplamlari hazirla... // bolme icin cagirinca da degeri geri cevir // nasil olsa bu evrede.."d"nin ilk ogesi veya kalani hic kullanilmiyor hueA += p[1] * Math.cos(p[0] * 2.0 * Math.PI); hueB += p[1] * Math.sin(p[0] * 2.0 * Math.PI); // doygunluk sat += p[1]; // aydinlik lum += p[2]; } /** * see basinDistance * * @param s * @return */ public double[] mean(double s) { double[] ort = new double[3]; ort[0] = Math.atan2(hueB,hueA); ort[0] = 0.5 * ort[0] / Math.PI; if (ort[0] < 0.0) ort[0] = 1.0 + ort[0]; ort[1] = sat / s; ort[2] = lum / s; return ort; } public static double[] mean(double[] p1,double[] p2) { double[] ort = new double[3]; // renk ozu double A = p1[1] * Math.cos(p1[0] * 2.0 * Math.PI) + p2[1] * Math.cos(p2[0] * 2.0 * Math.PI); double B = p1[1] * Math.sin(p1[0] * 2.0 * Math.PI) + p2[1] * Math.sin(p2[0] * 2.0 * Math.PI); ort[0] = Math.atan2(B,A); ort[0] = 0.5 * ort[0] / Math.PI; if (ort[0] < 0.0) ort[0] = 1.0 + ort[0]; // aydinlik ile doygunluk ort[1] = (p1[1] + p2[1]) / 2.0; ort[2] = (p1[2] + p2[2]) / 2.0; return ort; } public static double norm(double[] p,double[] w) { double norm = 0.0; for(int i = 0; i < p.length; i++) norm += p[i] * p[i] * w[i]; return Math.sqrt(norm); } /** * see distance * * @param p1 * @param p2 * @return */ public static double[] difference(double[] p1,double[] p2) { if(p1.length != p2.length){ System.err.println("Incompatible vector lengths"); return null; } double[] fark = new double[p1.length]; fark[2] = p1[2]-p2[2]; fark[1] = p1[1]-p2[1]; //fark[0] = p1[0]-p2[0]; fark[0] = Tools.hueDistance(p1[0],p2[0]) * 2.0; return fark; } }