Loading src/main/java/com/elphel/imagej/orthomosaic/OrthoMap.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -2680,7 +2680,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{ gd.addNumericField("Video output frame rate", video_fps, 3,7,"fps", "Frame rate of the video."); gd.addNumericField("Video output frame rate", video_fps, 3,7,"fps", "Frame rate of the video."); gd.addCheckbox ("Compress AVI with JPEG", avi_compress_jpeg, "Use JPEG for AVI compression (false - use raw)."); gd.addCheckbox ("Compress AVI with JPEG", avi_compress_jpeg, "Use JPEG for AVI compression (false - use raw)."); gd.addNumericField("AVI JPEG quality", aviJpegQuality, 0, 4, "", "AVI JPEG quality if JPEG compression is used."); gd.addNumericField("AVI JPEG quality", aviJpegQuality, 0, 4, "", "AVI JPEG quality if JPEG compression is used."); gd.addCheckbox ("Convert AVI to WEBM", run_ffmpeg, "Use ffmped to convert intermediate AVI video to WEBM."); gd.addCheckbox ("Convert AVI to WEBM", run_ffmpeg, "Use ffmpeg to convert intermediate AVI video to WEBM."); gd.addStringField ("WEBM output extension", video_ext, 5,"WEBM output file extension including dot, normally \".webm\"."); gd.addStringField ("WEBM output extension", video_ext, 5,"WEBM output file extension including dot, normally \".webm\"."); gd.addStringField ("WEBM codec", video_codec, 5,"WEBM codec \"vp8\" or \"vp9\"(vp9 had problems)."); gd.addStringField ("WEBM codec", video_codec, 5,"WEBM codec \"vp8\" or \"vp9\"(vp9 had problems)."); gd.addNumericField("WEBM CRF", video_crf, 0, 4, "", "WEBM compression quality (lower - better, 10 - good)."); gd.addNumericField("WEBM CRF", video_crf, 0, 4, "", "WEBM compression quality (lower - better, 10 - good)."); Loading src/main/java/com/elphel/imagej/tileprocessor/Correlation2d.java +178 −0 Original line number Original line Diff line number Diff line Loading @@ -10,6 +10,7 @@ import com.elphel.imagej.common.PolynomialApproximation; import com.elphel.imagej.common.ShowDoubleFloatArrays; import com.elphel.imagej.common.ShowDoubleFloatArrays; import com.elphel.imagej.tileprocessor.Corr2dLMA.Sample; import com.elphel.imagej.tileprocessor.Corr2dLMA.Sample; import Jama.EigenvalueDecomposition; import Jama.Matrix; import Jama.Matrix; /** /** Loading Loading @@ -2506,6 +2507,183 @@ public class Correlation2d { } } /** * * @param data * @param data_width * @param abs_min * @param rel_min * @param min_peak * @param eigen_sub_min - when calculating eigenvectors, subtract min from data, false - just skip * @param fpn_mask * @param ignore_border * @param debug_data null or double[1] * @param debug * @return {dx,dy,strength, eig_x, eig_y, lambda0, lambda1), [eig_x, eig_y] <-> labmda0, lambda0 < lambda1. */ public static double [] getMaxXYCmEig( double [] data, // will be modified if fpn_mask != null; int data_width, // = 2 * transform_size - 1; double abs_min, double rel_min, double min_peak, double eig_sub_frac, // subtract fraction of threshold {eig_min_abs,eig_min_rel} after selecting by them (0 - select only, will have pedestal) boolean [] fpn_mask, boolean ignore_border, // only if fpn_mask != null - ignore tile if maximum touches fpn_mask double [][] debug_data, // null or double [1] boolean debug) { int data_height = data.length/data_width; int center_xy = (data_width - 1)/2; // = transform_size - 1; double x0 = center_xy, y0 = center_xy; int imax= 0; for (int i= 1; i < data.length;i++) { if (Double.isNaN(data[i])) { System.out.println("NaN in getMaxXYCmEig()"); return null; } if (data[i] > data[imax]) { imax = i; } } if (data[imax] < min_peak) { return null; // too weak;even before fpn filter } int ix0 = imax % data_width; int iy0 = imax / data_width; x0 = ix0; y0 = iy0; //min_peak // if (fpn_mask != null if (fpn_mask != null) { // modifies data, returns null if hits fpn for (int i = 0; i < fpn_mask.length; i++) if (fpn_mask[i]) { int iy = i / data_width; int ix = i - iy * data_width; if (ignore_border) { if(((ix - ix0) <= 1) && ((ix - ix0) >= -1) && ((iy - iy0) <= 1) && ((iy - iy0) >= -1)) { return null; // new double[3]; } } int ix1 = 2 * ix0 - ix; if ((ix1 >= 0) && (ix1 < data_width)) { int iy1 = 2 * iy0 - iy; if ((iy1 >= 0) && (iy1 < data_height)) { data[iy1 * data_width + ix1] = 0.0; // zero out symmetrical to fpn mask around integer maximum } } } // update imax imax= 0; for (int i= 1; i < data.length;i++) { if (data[i] > data[imax]) { imax = i; } } if (data[imax] < min_peak) { return null; // too weak after fpn filter } } // create mask of connected to max pixels double mx = data[imax]; double min_d = Math.min(abs_min, rel_min*mx); // double sub_pedestal = min_d * eig_sub_frac; boolean [] above_threshold = new boolean [data.length]; for (int i = 0; i < data.length; i++) { above_threshold[i] = data[i] >= min_d; } boolean [] en_data = (new TileNeibs(data_width, data_height)).getConnected( above_threshold, // boolean [] tiles, ix0, // int seedX, iy0); // int seedY) // find centroid double s0 = 0, sx=0,sy = 0, sx2 = 0, sy2=0, sxy = 0; for (int iy = 0; iy < data_height; iy++) { double y = iy - y0; for (int ix = 0; ix < data_width; ix++) { int indx = iy * data_width + ix; if (en_data[indx]) { // assumes d >0, as it is >= min_d double x = ix - x0; double d = data[iy * data_width + ix] - sub_pedestal; s0 += d; sx += d * x; sy += d * y; sx2 += d * x * x; sy2 += d * y * y; sxy += d * x * y; } } } x0 += sx / s0; // relative to top-left y0 += sy / s0; /* double s0 = 0, sx=0,sy = 0; for (int iy = 0; iy < data_height; iy++) { double y = iy - y0; for (int ix = 0; ix < data_width; ix++) { int indx = iy * data_width + ix; if (en_data[indx]) { // assumes d >0, as it is >= min_d double x = ix - x0; double d = data[iy * data_width + ix] - sub_pedestal; s0 += d; sx += d * x; sy += d * y; } } } x0 += sx / s0; // relative to top-left y0 += sy / s0; double sx2 = 0, sy2=0, sxy = 0; for (int iy = 0; iy < data_height; iy++) { double y = iy - y0; for (int ix = 0; ix < data_width; ix++) { int indx = iy * data_width + ix; if (en_data[indx]) { // assumes d >0, as it is >= min_d double x = ix - x0; double d = data[iy * data_width + ix] - sub_pedestal; sx2 += d * x * x; sy2 += d * y * y; sxy += d * x * y; } } } */ //https://users.cs.utah.edu/~tch/CS4640/resources/A%20geometric%20interpretation%20of%20the%20covariance%20matrix.pdf double cxx = sx2 - sx * sx / s0, cyy= sy2 - sy * sy / s0, cxy = sxy - sx * sy / s0; Matrix covar = new Matrix(new double[][] {{cxx, cxy},{cxy,cyy}}); EigenvalueDecomposition eig = covar.eig(); double [] eigval = {eig.getD().get(0, 0),eig.getD().get(1, 1)}; double [][] eigvec = eig.getV().getArray(); // columns - vectors? int eig_indx = (eigval[0] > eigval[1]) ? 1 : 0; double [] rslt = { x0 - center_xy, y0 - center_xy, mx, eigvec[0][eig_indx], eigvec[1][eig_indx], eigval[eig_indx], eigval[1-eig_indx]}; if (debug){ System.out.println("getMaxXYCm() -> "+rslt[0]+":"+rslt[1]+" ("+rslt[2]+ "), eigv0=["+rslt[3]+","+rslt[4]+"], lambda0="+rslt[5]+", lambda1="+rslt[6]); } if (debug_data != null) { debug_data[0] = data.clone(); for (int i = 0; i < data.length; i++) { if (!en_data[i]) { debug_data[0][i] = Double.NaN; } } } return rslt; } /** /** * Find maximum of the 2d array projected on a specified vector using centroid. * Find maximum of the 2d array projected on a specified vector using centroid. * On the first stage integer maximum is found, then several refining operations * On the first stage integer maximum is found, then several refining operations Loading Loading
src/main/java/com/elphel/imagej/orthomosaic/OrthoMap.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -2680,7 +2680,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{ gd.addNumericField("Video output frame rate", video_fps, 3,7,"fps", "Frame rate of the video."); gd.addNumericField("Video output frame rate", video_fps, 3,7,"fps", "Frame rate of the video."); gd.addCheckbox ("Compress AVI with JPEG", avi_compress_jpeg, "Use JPEG for AVI compression (false - use raw)."); gd.addCheckbox ("Compress AVI with JPEG", avi_compress_jpeg, "Use JPEG for AVI compression (false - use raw)."); gd.addNumericField("AVI JPEG quality", aviJpegQuality, 0, 4, "", "AVI JPEG quality if JPEG compression is used."); gd.addNumericField("AVI JPEG quality", aviJpegQuality, 0, 4, "", "AVI JPEG quality if JPEG compression is used."); gd.addCheckbox ("Convert AVI to WEBM", run_ffmpeg, "Use ffmped to convert intermediate AVI video to WEBM."); gd.addCheckbox ("Convert AVI to WEBM", run_ffmpeg, "Use ffmpeg to convert intermediate AVI video to WEBM."); gd.addStringField ("WEBM output extension", video_ext, 5,"WEBM output file extension including dot, normally \".webm\"."); gd.addStringField ("WEBM output extension", video_ext, 5,"WEBM output file extension including dot, normally \".webm\"."); gd.addStringField ("WEBM codec", video_codec, 5,"WEBM codec \"vp8\" or \"vp9\"(vp9 had problems)."); gd.addStringField ("WEBM codec", video_codec, 5,"WEBM codec \"vp8\" or \"vp9\"(vp9 had problems)."); gd.addNumericField("WEBM CRF", video_crf, 0, 4, "", "WEBM compression quality (lower - better, 10 - good)."); gd.addNumericField("WEBM CRF", video_crf, 0, 4, "", "WEBM compression quality (lower - better, 10 - good)."); Loading
src/main/java/com/elphel/imagej/tileprocessor/Correlation2d.java +178 −0 Original line number Original line Diff line number Diff line Loading @@ -10,6 +10,7 @@ import com.elphel.imagej.common.PolynomialApproximation; import com.elphel.imagej.common.ShowDoubleFloatArrays; import com.elphel.imagej.common.ShowDoubleFloatArrays; import com.elphel.imagej.tileprocessor.Corr2dLMA.Sample; import com.elphel.imagej.tileprocessor.Corr2dLMA.Sample; import Jama.EigenvalueDecomposition; import Jama.Matrix; import Jama.Matrix; /** /** Loading Loading @@ -2506,6 +2507,183 @@ public class Correlation2d { } } /** * * @param data * @param data_width * @param abs_min * @param rel_min * @param min_peak * @param eigen_sub_min - when calculating eigenvectors, subtract min from data, false - just skip * @param fpn_mask * @param ignore_border * @param debug_data null or double[1] * @param debug * @return {dx,dy,strength, eig_x, eig_y, lambda0, lambda1), [eig_x, eig_y] <-> labmda0, lambda0 < lambda1. */ public static double [] getMaxXYCmEig( double [] data, // will be modified if fpn_mask != null; int data_width, // = 2 * transform_size - 1; double abs_min, double rel_min, double min_peak, double eig_sub_frac, // subtract fraction of threshold {eig_min_abs,eig_min_rel} after selecting by them (0 - select only, will have pedestal) boolean [] fpn_mask, boolean ignore_border, // only if fpn_mask != null - ignore tile if maximum touches fpn_mask double [][] debug_data, // null or double [1] boolean debug) { int data_height = data.length/data_width; int center_xy = (data_width - 1)/2; // = transform_size - 1; double x0 = center_xy, y0 = center_xy; int imax= 0; for (int i= 1; i < data.length;i++) { if (Double.isNaN(data[i])) { System.out.println("NaN in getMaxXYCmEig()"); return null; } if (data[i] > data[imax]) { imax = i; } } if (data[imax] < min_peak) { return null; // too weak;even before fpn filter } int ix0 = imax % data_width; int iy0 = imax / data_width; x0 = ix0; y0 = iy0; //min_peak // if (fpn_mask != null if (fpn_mask != null) { // modifies data, returns null if hits fpn for (int i = 0; i < fpn_mask.length; i++) if (fpn_mask[i]) { int iy = i / data_width; int ix = i - iy * data_width; if (ignore_border) { if(((ix - ix0) <= 1) && ((ix - ix0) >= -1) && ((iy - iy0) <= 1) && ((iy - iy0) >= -1)) { return null; // new double[3]; } } int ix1 = 2 * ix0 - ix; if ((ix1 >= 0) && (ix1 < data_width)) { int iy1 = 2 * iy0 - iy; if ((iy1 >= 0) && (iy1 < data_height)) { data[iy1 * data_width + ix1] = 0.0; // zero out symmetrical to fpn mask around integer maximum } } } // update imax imax= 0; for (int i= 1; i < data.length;i++) { if (data[i] > data[imax]) { imax = i; } } if (data[imax] < min_peak) { return null; // too weak after fpn filter } } // create mask of connected to max pixels double mx = data[imax]; double min_d = Math.min(abs_min, rel_min*mx); // double sub_pedestal = min_d * eig_sub_frac; boolean [] above_threshold = new boolean [data.length]; for (int i = 0; i < data.length; i++) { above_threshold[i] = data[i] >= min_d; } boolean [] en_data = (new TileNeibs(data_width, data_height)).getConnected( above_threshold, // boolean [] tiles, ix0, // int seedX, iy0); // int seedY) // find centroid double s0 = 0, sx=0,sy = 0, sx2 = 0, sy2=0, sxy = 0; for (int iy = 0; iy < data_height; iy++) { double y = iy - y0; for (int ix = 0; ix < data_width; ix++) { int indx = iy * data_width + ix; if (en_data[indx]) { // assumes d >0, as it is >= min_d double x = ix - x0; double d = data[iy * data_width + ix] - sub_pedestal; s0 += d; sx += d * x; sy += d * y; sx2 += d * x * x; sy2 += d * y * y; sxy += d * x * y; } } } x0 += sx / s0; // relative to top-left y0 += sy / s0; /* double s0 = 0, sx=0,sy = 0; for (int iy = 0; iy < data_height; iy++) { double y = iy - y0; for (int ix = 0; ix < data_width; ix++) { int indx = iy * data_width + ix; if (en_data[indx]) { // assumes d >0, as it is >= min_d double x = ix - x0; double d = data[iy * data_width + ix] - sub_pedestal; s0 += d; sx += d * x; sy += d * y; } } } x0 += sx / s0; // relative to top-left y0 += sy / s0; double sx2 = 0, sy2=0, sxy = 0; for (int iy = 0; iy < data_height; iy++) { double y = iy - y0; for (int ix = 0; ix < data_width; ix++) { int indx = iy * data_width + ix; if (en_data[indx]) { // assumes d >0, as it is >= min_d double x = ix - x0; double d = data[iy * data_width + ix] - sub_pedestal; sx2 += d * x * x; sy2 += d * y * y; sxy += d * x * y; } } } */ //https://users.cs.utah.edu/~tch/CS4640/resources/A%20geometric%20interpretation%20of%20the%20covariance%20matrix.pdf double cxx = sx2 - sx * sx / s0, cyy= sy2 - sy * sy / s0, cxy = sxy - sx * sy / s0; Matrix covar = new Matrix(new double[][] {{cxx, cxy},{cxy,cyy}}); EigenvalueDecomposition eig = covar.eig(); double [] eigval = {eig.getD().get(0, 0),eig.getD().get(1, 1)}; double [][] eigvec = eig.getV().getArray(); // columns - vectors? int eig_indx = (eigval[0] > eigval[1]) ? 1 : 0; double [] rslt = { x0 - center_xy, y0 - center_xy, mx, eigvec[0][eig_indx], eigvec[1][eig_indx], eigval[eig_indx], eigval[1-eig_indx]}; if (debug){ System.out.println("getMaxXYCm() -> "+rslt[0]+":"+rslt[1]+" ("+rslt[2]+ "), eigv0=["+rslt[3]+","+rslt[4]+"], lambda0="+rslt[5]+", lambda1="+rslt[6]); } if (debug_data != null) { debug_data[0] = data.clone(); for (int i = 0; i < data.length; i++) { if (!en_data[i]) { debug_data[0][i] = Double.NaN; } } } return rslt; } /** /** * Find maximum of the 2d array projected on a specified vector using centroid. * Find maximum of the 2d array projected on a specified vector using centroid. * On the first stage integer maximum is found, then several refining operations * On the first stage integer maximum is found, then several refining operations Loading