List of usage examples for org.opencv.core Mat rows
public int rows()
From source file:org.akvo.caddisfly.helper.ImageHelper.java
License:Open Source License
/** * Gets the center of the backdrop in the test chamber * * @param bitmap the photo to analyse/*from w w w . jav a 2 s. c om*/ * @return the center point of the found circle */ public static Point getCenter(@NonNull Bitmap bitmap) { // convert bitmap to mat Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC1); Mat grayMat = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC1); Utils.bitmapToMat(bitmap, mat); // convert to grayScale int colorChannels = (mat.channels() == 3) ? Imgproc.COLOR_BGR2GRAY : ((mat.channels() == 4) ? Imgproc.COLOR_BGRA2GRAY : 1); Imgproc.cvtColor(mat, grayMat, colorChannels); // reduce the noise so we avoid false circle detection //Imgproc.GaussianBlur(grayMat, grayMat, new Size(9, 9), 2, 2); // param1 = gradient value used to handle edge detection // param2 = Accumulator threshold value for the // cv2.CV_HOUGH_GRADIENT method. // The smaller the threshold is, the more circles will be // detected (including false circles). // The larger the threshold is, the more circles will // potentially be returned. double param1 = 10, param2 = 100; // create a Mat object to store the circles detected Mat circles = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC1); // find the circle in the image Imgproc.HoughCircles(grayMat, circles, Imgproc.CV_HOUGH_GRADIENT, RESOLUTION_INVERSE_RATIO, (double) MIN_CIRCLE_CENTER_DISTANCE, param1, param2, MIN_RADIUS, MAX_RADIUS); int numberOfCircles = (circles.rows() == 0) ? 0 : circles.cols(); // draw the circles found on the image if (numberOfCircles > 0) { double[] circleCoordinates = circles.get(0, 0); int x = (int) circleCoordinates[0], y = (int) circleCoordinates[1]; org.opencv.core.Point center = new org.opencv.core.Point(x, y); int foundRadius = (int) circleCoordinates[2]; // circle outline Imgproc.circle(mat, center, foundRadius, COLOR_GREEN, 4); Utils.matToBitmap(mat, bitmap); return new Point((int) center.x, (int) center.y); } return null; }
From source file:org.akvo.caddisfly.sensor.colorimetry.strip.calibration.CalibrationCard.java
License:Open Source License
@NonNull public static double[][] createWhitePointArray(@NonNull Mat lab, @NonNull CalibrationData calData) { List<CalibrationData.WhiteLine> lines = calData.getWhiteLines(); int numLines = lines.size() * 10; // on each line, we sample 10 points double[][] points = new double[numLines][5]; int index = 0; calData.hSizePixel = lab.cols();//from w w w. j av a 2 s.c o m double hPixels = calData.hSizePixel / calData.hSize; // pixel per mm in the horizontal direction calData.vSizePixel = lab.rows(); double vPixels = calData.vSizePixel / calData.vSize; // pixel per mm in the vertical direction for (CalibrationData.WhiteLine line : lines) { double xStart = line.getPosition()[0]; double yStart = line.getPosition()[1]; double xEnd = line.getPosition()[2]; double yEnd = line.getPosition()[3]; double xDiff = (xEnd - xStart) * ONE_OVER_NINE; double yDiff = (yEnd - yStart) * ONE_OVER_NINE; int dp = (int) Math.round(line.getWidth() * hPixels * 0.5); if (dp == 0) { dp = 1; // minimum of one pixel } // sample line for (int i = 0; i <= 9; i++) { int xp = (int) Math.round((xStart + i * xDiff) * hPixels); int yp = (int) Math.round((yStart + i * yDiff) * vPixels); points[index * 10 + i][0] = xp; points[index * 10 + i][1] = yp; double[] whiteVal = getWhiteVal(lab, xp, yp, dp); points[index * 10 + i][2] = whiteVal[0]; points[index * 10 + i][3] = whiteVal[1]; points[index * 10 + i][4] = whiteVal[2]; } index++; } return points; }
From source file:org.akvo.caddisfly.sensor.colorimetry.strip.calibration.CalibrationCard.java
License:Open Source License
@NonNull private static Mat doIlluminationCorrection(@NonNull Mat imgLab, @NonNull CalibrationData calData) { // create HLS image for homogeneous illumination calibration int pHeight = imgLab.rows(); int pWidth = imgLab.cols(); RealMatrix points = createWhitePointMatrix(imgLab, calData); // create coefficient matrix for all three variables L,A,B // the model for all three is y = ax + bx^2 + cy + dy^2 + exy + f // 6th row is the constant 1 RealMatrix coefficient = new Array2DRowRealMatrix(points.getRowDimension(), 6); coefficient.setColumnMatrix(0, points.getColumnMatrix(0)); coefficient.setColumnMatrix(2, points.getColumnMatrix(1)); //create constant, x^2, y^2 and xy terms for (int i = 0; i < points.getRowDimension(); i++) { coefficient.setEntry(i, 1, Math.pow(coefficient.getEntry(i, 0), 2)); // x^2 coefficient.setEntry(i, 3, Math.pow(coefficient.getEntry(i, 2), 2)); // y^2 coefficient.setEntry(i, 4, coefficient.getEntry(i, 0) * coefficient.getEntry(i, 2)); // xy coefficient.setEntry(i, 5, 1d); // constant = 1 }/*from w w w. j av a 2s . c o m*/ // create vectors RealVector L = points.getColumnVector(2); RealVector A = points.getColumnVector(3); RealVector B = points.getColumnVector(4); // solve the least squares problem for all three variables DecompositionSolver solver = new SingularValueDecomposition(coefficient).getSolver(); RealVector solutionL = solver.solve(L); RealVector solutionA = solver.solve(A); RealVector solutionB = solver.solve(B); // get individual coefficients float La = (float) solutionL.getEntry(0); float Lb = (float) solutionL.getEntry(1); float Lc = (float) solutionL.getEntry(2); float Ld = (float) solutionL.getEntry(3); float Le = (float) solutionL.getEntry(4); float Lf = (float) solutionL.getEntry(5); float Aa = (float) solutionA.getEntry(0); float Ab = (float) solutionA.getEntry(1); float Ac = (float) solutionA.getEntry(2); float Ad = (float) solutionA.getEntry(3); float Ae = (float) solutionA.getEntry(4); float Af = (float) solutionA.getEntry(5); float Ba = (float) solutionB.getEntry(0); float Bb = (float) solutionB.getEntry(1); float Bc = (float) solutionB.getEntry(2); float Bd = (float) solutionB.getEntry(3); float Be = (float) solutionB.getEntry(4); float Bf = (float) solutionB.getEntry(5); // compute mean (the luminosity value of the plane in the middle of the image) float L_mean = (float) (0.5 * La * pWidth + 0.5 * Lc * pHeight + Lb * pWidth * pWidth / 3.0 + Ld * pHeight * pHeight / 3.0 + Le * 0.25 * pHeight * pWidth + Lf); float A_mean = (float) (0.5 * Aa * pWidth + 0.5 * Ac * pHeight + Ab * pWidth * pWidth / 3.0 + Ad * pHeight * pHeight / 3.0 + Ae * 0.25 * pHeight * pWidth + Af); float B_mean = (float) (0.5 * Ba * pWidth + 0.5 * Bc * pHeight + Bb * pWidth * pWidth / 3.0 + Bd * pHeight * pHeight / 3.0 + Be * 0.25 * pHeight * pWidth + Bf); // Correct image // we do this per row. We tried to do it in one block, but there is no speed difference. byte[] temp = new byte[imgLab.cols() * imgLab.channels()]; int valL, valA, valB; int ii, ii3; float iiSq, iSq; int imgCols = imgLab.cols(); int imgRows = imgLab.rows(); // use lookup tables to speed up computation // create lookup tables float[] L_aii = new float[imgCols]; float[] L_biiSq = new float[imgCols]; float[] A_aii = new float[imgCols]; float[] A_biiSq = new float[imgCols]; float[] B_aii = new float[imgCols]; float[] B_biiSq = new float[imgCols]; float[] Lci = new float[imgRows]; float[] LdiSq = new float[imgRows]; float[] Aci = new float[imgRows]; float[] AdiSq = new float[imgRows]; float[] Bci = new float[imgRows]; float[] BdiSq = new float[imgRows]; for (ii = 0; ii < imgCols; ii++) { iiSq = ii * ii; L_aii[ii] = La * ii; L_biiSq[ii] = Lb * iiSq; A_aii[ii] = Aa * ii; A_biiSq[ii] = Ab * iiSq; B_aii[ii] = Ba * ii; B_biiSq[ii] = Bb * iiSq; } for (int i = 0; i < imgRows; i++) { iSq = i * i; Lci[i] = Lc * i; LdiSq[i] = Ld * iSq; Aci[i] = Ac * i; AdiSq[i] = Ad * iSq; Bci[i] = Bc * i; BdiSq[i] = Bd * iSq; } // We can also improve the performance of the i,ii term, if we want, but it won't make much difference. for (int i = 0; i < imgRows; i++) { // y imgLab.get(i, 0, temp); ii3 = 0; for (ii = 0; ii < imgCols; ii++) { //x valL = capValue( Math.round((temp[ii3] & 0xFF) - (L_aii[ii] + L_biiSq[ii] + Lci[i] + LdiSq[i] + Le * i * ii + Lf) + L_mean), 0, 255); valA = capValue( Math.round((temp[ii3 + 1] & 0xFF) - (A_aii[ii] + A_biiSq[ii] + Aci[i] + AdiSq[i] + Ae * i * ii + Af) + A_mean), 0, 255); valB = capValue( Math.round((temp[ii3 + 2] & 0xFF) - (B_aii[ii] + B_biiSq[ii] + Bci[i] + BdiSq[i] + Be * i * ii + Bf) + B_mean), 0, 255); temp[ii3] = (byte) valL; temp[ii3 + 1] = (byte) valA; temp[ii3 + 2] = (byte) valB; ii3 += 3; } imgLab.put(i, 0, temp); } return imgLab; }
From source file:org.akvo.caddisfly.sensor.colorimetry.strip.calibration.CalibrationCard.java
License:Open Source License
@NonNull private static float[] measurePatch(@NonNull Mat imgMat, double x, double y, @NonNull CalibrationData calData) { float[] LAB_result = new float[3]; float totL = 0; float totA = 0; float totB = 0; int totNum = 0; calData.hSizePixel = imgMat.cols();// w w w . j a v a 2s .co m double hPixels = calData.hSizePixel / calData.hSize; // pixel per mm calData.vSizePixel = imgMat.rows(); double vPixels = calData.vSizePixel / calData.vSize; // pixel per mm int xp = (int) Math.round(x * hPixels); int yp = (int) Math.round(y * vPixels); int dp = (int) Math.round(calData.getPatchSize() * hPixels * 0.25); byte[] temp = new byte[(2 * dp + 1) * imgMat.channels()]; int ii3; for (int i = -dp; i <= dp; i++) { imgMat.get(yp - i, xp - dp, temp); ii3 = 0; for (int ii = 0; ii <= 2 * dp; ii++) { totL += temp[ii3] & 0xFF; //imgMat.get(yp + i, xp + ii)[0]; totA += temp[ii3 + 1] & 0xFF; //imgMat.get(yp + i, xp + ii)[1]; totB += temp[ii3 + 2] & 0xFF; //imgMat.get(yp + i, xp + ii)[2]; totNum++; ii3 += 3; } } LAB_result[0] = totL / totNum; LAB_result[1] = totA / totNum; LAB_result[2] = totB / totNum; return LAB_result; }
From source file:org.akvo.caddisfly.sensor.colorimetry.strip.calibration.CalibrationCard.java
License:Open Source License
@NonNull private static Mat do1D_3DCorrection(@NonNull Mat imgMat, @Nullable CalibrationData calData) throws CalibrationException { if (calData == null) { throw new CalibrationException("no calibration data."); }// w ww. j ava 2 s. c om final WeightedObservedPoints obsL = new WeightedObservedPoints(); final WeightedObservedPoints obsA = new WeightedObservedPoints(); final WeightedObservedPoints obsB = new WeightedObservedPoints(); Map<String, double[]> calResultIllumination = new HashMap<>(); // iterate over all patches try { for (String label : calData.getCalValues().keySet()) { CalibrationData.CalValue cal = calData.getCalValues().get(label); CalibrationData.Location loc = calData.getLocations().get(label); float[] LAB_color = measurePatch(imgMat, loc.x, loc.y, calData); // measure patch color obsL.add(LAB_color[0], cal.getL()); obsA.add(LAB_color[1], cal.getA()); obsB.add(LAB_color[2], cal.getB()); calResultIllumination.put(label, new double[] { LAB_color[0], LAB_color[1], LAB_color[2] }); } } catch (Exception e) { throw new CalibrationException("1D calibration: error iterating over all patches.", e); } // Instantiate a second-degree polynomial fitter. final PolynomialCurveFitter fitter = PolynomialCurveFitter.create(2); // Retrieve fitted parameters (coefficients of the polynomial function). // order of coefficients is (c + bx + ax^2), so [c,b,a] try { final double[] coefficientL = fitter.fit(obsL.toList()); final double[] coefficientA = fitter.fit(obsA.toList()); final double[] coefficientB = fitter.fit(obsB.toList()); double[] valIllumination; double L_orig, A_orig, B_orig, L_new, A_new, B_new; // transform patch values using the 1d calibration results Map<String, double[]> calResult1D = new HashMap<>(); for (String label : calData.getCalValues().keySet()) { valIllumination = calResultIllumination.get(label); L_orig = valIllumination[0]; A_orig = valIllumination[1]; B_orig = valIllumination[2]; L_new = coefficientL[2] * L_orig * L_orig + coefficientL[1] * L_orig + coefficientL[0]; A_new = coefficientA[2] * A_orig * A_orig + coefficientA[1] * A_orig + coefficientA[0]; B_new = coefficientB[2] * B_orig * B_orig + coefficientB[1] * B_orig + coefficientB[0]; calResult1D.put(label, new double[] { L_new, A_new, B_new }); } // use the 1D calibration result for the second calibration step // Following http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html#solving-linear-least-squares-problems-and-pseudo-inverses // we will solve P = M x int total = calData.getLocations().keySet().size(); RealMatrix coefficient = new Array2DRowRealMatrix(total, 3); RealMatrix cal = new Array2DRowRealMatrix(total, 3); int index = 0; // create coefficient and calibration vectors for (String label : calData.getCalValues().keySet()) { CalibrationData.CalValue calv = calData.getCalValues().get(label); double[] cal1dResult = calResult1D.get(label); coefficient.setEntry(index, 0, cal1dResult[0]); coefficient.setEntry(index, 1, cal1dResult[1]); coefficient.setEntry(index, 2, cal1dResult[2]); cal.setEntry(index, 0, calv.getL()); cal.setEntry(index, 1, calv.getA()); cal.setEntry(index, 2, calv.getB()); index++; } DecompositionSolver solver = new SingularValueDecomposition(coefficient).getSolver(); RealMatrix sol = solver.solve(cal); float a_L, b_L, c_L, a_A, b_A, c_A, a_B, b_B, c_B; a_L = (float) sol.getEntry(0, 0); b_L = (float) sol.getEntry(1, 0); c_L = (float) sol.getEntry(2, 0); a_A = (float) sol.getEntry(0, 1); b_A = (float) sol.getEntry(1, 1); c_A = (float) sol.getEntry(2, 1); a_B = (float) sol.getEntry(0, 2); b_B = (float) sol.getEntry(1, 2); c_B = (float) sol.getEntry(2, 2); //use the solution to correct the image double L_temp, A_temp, B_temp, L_mid, A_mid, B_mid; int L_fin, A_fin, B_fin; int ii3; byte[] temp = new byte[imgMat.cols() * imgMat.channels()]; for (int i = 0; i < imgMat.rows(); i++) { // y imgMat.get(i, 0, temp); ii3 = 0; for (int ii = 0; ii < imgMat.cols(); ii++) { //x L_temp = temp[ii3] & 0xFF; A_temp = temp[ii3 + 1] & 0xFF; B_temp = temp[ii3 + 2] & 0xFF; L_mid = coefficientL[2] * L_temp * L_temp + coefficientL[1] * L_temp + coefficientL[0]; A_mid = coefficientA[2] * A_temp * A_temp + coefficientA[1] * A_temp + coefficientA[0]; B_mid = coefficientB[2] * B_temp * B_temp + coefficientB[1] * B_temp + coefficientB[0]; L_fin = (int) Math.round(a_L * L_mid + b_L * A_mid + c_L * B_mid); A_fin = (int) Math.round(a_A * L_mid + b_A * A_mid + c_A * B_mid); B_fin = (int) Math.round(a_B * L_mid + b_B * A_mid + c_B * B_mid); // cap values L_fin = capValue(L_fin, 0, 255); A_fin = capValue(A_fin, 0, 255); B_fin = capValue(B_fin, 0, 255); temp[ii3] = (byte) L_fin; temp[ii3 + 1] = (byte) A_fin; temp[ii3 + 2] = (byte) B_fin; ii3 += 3; } imgMat.put(i, 0, temp); } return imgMat; } catch (Exception e) { throw new CalibrationException("error while performing calibration: ", e); } }
From source file:org.akvo.caddisfly.sensor.colorimetry.strip.calibration.CalibrationCard.java
License:Open Source License
private static void addPatch(@NonNull Mat imgMat, Double x, Double y, @NonNull CalibrationData calData, String label) {//from w w w.j a v a 2 s . co m CalibrationData.CalValue calValue = calData.getCalValues().get(label); calData.hSizePixel = imgMat.cols(); double hPixels = calData.hSizePixel / calData.hSize; // pixel per mm calData.vSizePixel = imgMat.rows(); double vPixels = calData.vSizePixel / calData.vSize; // pixel per mm int xp = (int) Math.round(x * hPixels); int yp = (int) Math.round(y * vPixels); int dp = (int) Math.round(calData.getPatchSize() * hPixels * 0.150); for (int i = -dp; i <= dp; i++) { for (int ii = -dp; ii <= dp; ii++) { byte[] col = new byte[3]; col[0] = (byte) Math.round(calValue.getL()); col[1] = (byte) Math.round(calValue.getA()); col[2] = (byte) Math.round(calValue.getB()); imgMat.put(yp + i, xp + ii, col); } } }
From source file:org.akvo.caddisfly.sensor.colorimetry.strip.detect.DetectStripTask.java
License:Open Source License
@Nullable @Override/* w ww . j a v a 2s .c o m*/ protected Void doInBackground(Intent... params) { Intent intent = params[0]; if (intent == null) { return null; } String uuid = intent.getStringExtra(Constant.UUID); StripTest stripTest = new StripTest(); int numPatches = stripTest.getPatchCount(uuid); format = intent.getIntExtra(Constant.FORMAT, ImageFormat.NV21); width = intent.getIntExtra(Constant.WIDTH, 0); height = intent.getIntExtra(Constant.HEIGHT, 0); if (width == 0 || height == 0) { return null; } JSONArray imagePatchArray = null; int imageCount = -1; Mat labImg; // Mat for image from NV21 data Mat labStrip; // Mat for detected strip try { String json = FileUtil.readFromInternalStorage(context, Constant.IMAGE_PATCH); imagePatchArray = new JSONArray(json); } catch (Exception e) { Timber.e(e); } for (int i = 0; i < numPatches; i++) { try { if (imagePatchArray != null) { // sub-array for each patch JSONArray array = imagePatchArray.getJSONArray(i); // get the image number from the json array int imageNo = array.getInt(0); if (imageNo > imageCount) { // Set imageCount to current number imageCount = imageNo; byte[] data = FileUtil.readByteArray(context, Constant.DATA + imageNo); if (data == null) { throw new IOException(); } //make a L,A,B Mat object from data try { labImg = makeLab(data); } catch (Exception e) { if (context != null) { Timber.e(e); } continue; } //perspectiveTransform try { if (labImg != null) { warp(labImg, imageNo); } } catch (Exception e) { if (context != null) { Timber.e(e); } continue; } //divide into calibration and strip areas try { if (context != null) { divideIntoCalibrationAndStripArea(); } } catch (Exception e) { Timber.e(e); continue; } //save warped image to external storage // if (DEVELOP_MODE) { // Mat rgb = new Mat(); // Imgproc.cvtColor(warpMat, rgb, Imgproc.COLOR_Lab2RGB); // Bitmap bitmap = Bitmap.createBitmap(rgb.width(), rgb.height(), Bitmap.Config.ARGB_8888); // Utils.matToBitmap(rgb, bitmap); // // //if (FileUtil.isExternalStorageWritable()) { // FileUtil.writeBitmapToExternalStorage(bitmap, "/warp", UUID.randomUUID().toString() + ".png"); //} // //Bitmap.createScaledBitmap(bitmap, BITMAP_SCALED_WIDTH, BITMAP_SCALED_HEIGHT, false); // } //calibrate Mat calibrationMat; try { CalibrationResultData calResult = getCalibratedImage(warpMat); if (calResult == null) { return null; } else { calibrationMat = calResult.getCalibratedImage(); } // Log.d(this.getClass().getSimpleName(), "E94 error mean: " + String.format(Locale.US, "%.2f", calResult.meanE94) // + ", max: " + String.format(Locale.US, "%.2f", calResult.maxE94) // + ", total: " + String.format(Locale.US, "%.2f", calResult.totalE94)); // if (AppPreferences.isDiagnosticMode()) { // listener.showError("E94 mean: " + String.format(Locale.US, "%.2f", calResult.meanE94) // + ", max: " + String.format(Locale.US, "%.2f", calResult.maxE94) // + ", total: " + String.format(Locale.US, "%.2f", calResult.totalE94)); // } } catch (Exception e) { Timber.e(e); return null; } //show calibrated image // if (DEVELOP_MODE) { // Mat rgb = new Mat(); // Imgproc.cvtColor(calibrationMat, rgb, Imgproc.COLOR_Lab2RGB); // Bitmap bitmap = Bitmap.createBitmap(rgb.width(), rgb.height(), Bitmap.Config.ARGB_8888); // Utils.matToBitmap(rgb, bitmap); // if (FileUtil.isExternalStorageWritable()) { // FileUtil.writeBitmapToExternalStorage(bitmap, "/warp", UUID.randomUUID().toString() + "_cal.png"); // } // //Bitmap.createScaledBitmap(bitmap, BITMAP_SCALED_WIDTH, BITMAP_SCALED_HEIGHT, false); // } // cut out black area that contains the strip Mat stripArea = null; if (roiStripArea != null) { stripArea = calibrationMat.submat(roiStripArea); } if (stripArea != null) { Mat strip = null; try { StripTest.Brand brand = stripTest.getBrand(uuid); strip = OpenCVUtil.detectStrip(stripArea, brand, ratioW, ratioH); } catch (Exception e) { Timber.e(e); } String error = ""; if (strip != null) { labStrip = strip.clone(); } else { if (context != null) { Timber.e(context.getString(R.string.error_calibrating)); } labStrip = stripArea.clone(); error = Constant.ERROR; //draw a red cross over the image Scalar red = RED_LAB_COLOR; // Lab color Imgproc.line(labStrip, new Point(0, 0), new Point(labStrip.cols(), labStrip.rows()), red, 2); Imgproc.line(labStrip, new Point(0, labStrip.rows()), new Point(labStrip.cols(), 0), red, 2); } try { // create byte[] from Mat and store it in internal storage // In order to restore the byte array, we also need the rows and columns dimensions // these are stored in the last 8 bytes int dataSize = labStrip.cols() * labStrip.rows() * 3; byte[] payload = new byte[dataSize + 8]; byte[] matByteArray = new byte[dataSize]; labStrip.get(0, 0, matByteArray); // pack cols and rows into byte arrays byte[] rows = FileUtil.leIntToByteArray(labStrip.rows()); byte[] cols = FileUtil.leIntToByteArray(labStrip.cols()); // append them to the end of the array, in order rows, cols System.arraycopy(matByteArray, 0, payload, 0, dataSize); System.arraycopy(rows, 0, payload, dataSize, 4); System.arraycopy(cols, 0, payload, dataSize + 4, 4); FileUtil.writeByteArray(context, payload, Constant.STRIP + imageNo + error); } catch (Exception e) { Timber.e(e); } } } } } catch (@NonNull JSONException | IOException e) { if (context != null) { Timber.e(context.getString(R.string.error_cut_out_strip)); } } } return null; }
From source file:org.akvo.caddisfly.sensor.colorimetry.strip.util.OpenCVUtil.java
License:Open Source License
@SuppressWarnings("UnusedParameters") public static Mat detectStrip(Mat stripArea, StripTest.Brand brand, double ratioW, double ratioH) { List<Mat> channels = new ArrayList<>(); Mat sArea = stripArea.clone();// w w w.j ava2 s . c o m // Gaussian blur Imgproc.medianBlur(sArea, sArea, 3); Core.split(sArea, channels); // create binary image Mat binary = new Mat(); // determine min and max NOT USED Imgproc.threshold(channels.get(0), binary, 128, MAX_RGB_INT_VALUE, Imgproc.THRESH_BINARY); // compute first approximation of line through length of the strip final WeightedObservedPoints points = new WeightedObservedPoints(); final WeightedObservedPoints corrPoints = new WeightedObservedPoints(); double tot, yTot; for (int i = 0; i < binary.cols(); i++) { // iterate over cols tot = 0; yTot = 0; for (int j = 0; j < binary.rows(); j++) { // iterate over rows if (binary.get(j, i)[0] > 128) { yTot += j; tot++; } } if (tot > 0) { points.add((double) i, yTot / tot); } } // order of coefficients is (b + ax), so [b, a] final PolynomialCurveFitter fitter = PolynomialCurveFitter.create(1); List<WeightedObservedPoint> pointsList = points.toList(); final double[] coefficient = fitter.fit(pointsList); // second pass, remove outliers double estimate, actual; for (int i = 0; i < pointsList.size(); i++) { estimate = coefficient[1] * pointsList.get(i).getX() + coefficient[0]; actual = pointsList.get(i).getY(); if (actual > LOWER_PERCENTAGE_BOUND * estimate && actual < UPPER_PERCENTAGE_BOUND * estimate) { //if the point differs less than +/- 10%, keep the point corrPoints.add(pointsList.get(i).getX(), pointsList.get(i).getY()); } } final double[] coefficientCorr = fitter.fit(corrPoints.toList()); double slope = coefficientCorr[1]; double offset = coefficientCorr[0]; // compute rotation angle double rotAngleDeg = Math.atan(slope) * 180 / Math.PI; //determine a point on the line, in the middle of strip, in the horizontal middle of the whole image int midPointX = binary.cols() / 2; int midPointY = (int) Math.round(midPointX * slope + offset); // rotate around the midpoint, to straighten the binary strip Mat dstBinary = new Mat(binary.rows(), binary.cols(), binary.type()); Point center = new Point(midPointX, midPointY); Mat rotMat = Imgproc.getRotationMatrix2D(center, rotAngleDeg, 1.0); Imgproc.warpAffine(binary, dstBinary, rotMat, binary.size(), Imgproc.INTER_CUBIC + Imgproc.WARP_FILL_OUTLIERS); // also apply rotation to colored strip Mat dstStrip = new Mat(stripArea.rows(), stripArea.cols(), stripArea.type()); Imgproc.warpAffine(stripArea, dstStrip, rotMat, binary.size(), Imgproc.INTER_CUBIC + Imgproc.WARP_FILL_OUTLIERS); // Compute white points in each row double[] rowCount = new double[dstBinary.rows()]; int rowTot; for (int i = 0; i < dstBinary.rows(); i++) { // iterate over rows rowTot = 0; for (int j = 0; j < dstBinary.cols(); j++) { // iterate over cols if (dstBinary.get(i, j)[0] > 128) { rowTot++; } } rowCount[i] = rowTot; } // find width by finding rising and dropping edges // rising edge = largest positive difference // falling edge = largest negative difference int risePos = 0; int fallPos = 0; double riseVal = 0; double fallVal = 0; for (int i = 0; i < dstBinary.rows() - 1; i++) { if (rowCount[i + 1] - rowCount[i] > riseVal) { riseVal = rowCount[i + 1] - rowCount[i]; risePos = i + 1; } if (rowCount[i + 1] - rowCount[i] < fallVal) { fallVal = rowCount[i + 1] - rowCount[i]; fallPos = i; } } // cut out binary strip Point stripTopLeft = new Point(0, risePos); Point stripBottomRight = new Point(dstBinary.cols(), fallPos); org.opencv.core.Rect stripAreaRect = new org.opencv.core.Rect(stripTopLeft, stripBottomRight); Mat binaryStrip = dstBinary.submat(stripAreaRect); // also cut out colored strip Mat colorStrip = dstStrip.submat(stripAreaRect); // now right end of strip // method: first rising edge double[] colCount = new double[binaryStrip.cols()]; int colTotal; for (int i = 0; i < binaryStrip.cols(); i++) { // iterate over cols colTotal = 0; for (int j = 0; j < binaryStrip.rows(); j++) { // iterate over rows if (binaryStrip.get(j, i)[0] > 128) { colTotal++; } } //Log.d("Caddisfly", String.valueOf(colTotal)); colCount[i] = colTotal; } stripAreaRect = getStripRectangle(binaryStrip, colCount, brand.getStripLength(), ratioW); Mat resultStrip = colorStrip.submat(stripAreaRect).clone(); // release Mat objects stripArea.release(); sArea.release(); binary.release(); dstBinary.release(); dstStrip.release(); binaryStrip.release(); colorStrip.release(); return resultStrip; }
From source file:org.akvo.caddisfly.sensor.colorimetry.strip.util.OpenCVUtil.java
License:Open Source License
private static Rect getStripRectangle(Mat binaryStrip, double[] colCount, double stripLength, double ratioW) { // threshold is that half of the rows in a column should be white int threshold = binaryStrip.rows() / 2; boolean found = false; // moving from the left, determine the first point that crosses the threshold double posLeft = 0; while (!found && posLeft < binaryStrip.cols()) { if (colCount[(int) posLeft] > threshold) { found = true;/*from w w w. j av a2s. com*/ } else { posLeft++; } } //use known length of strip to determine right side double posRight = posLeft + (stripLength * ratioW); found = false; // moving from the right, determine the first point that crosses the threshold int posRightTemp = binaryStrip.cols() - 1; while (!found && posRightTemp > 0) { if (colCount[posRightTemp] > threshold) { found = true; } else { posRightTemp--; } } // if there is a big difference in the right position determined by the two above methods // then ignore the first method above and determine the left position by second method only if (Math.abs(posRightTemp - posRight) > 5) { // use known length of strip to determine left side posLeft = posRightTemp - (stripLength * ratioW); posRight = posRightTemp; } // cut out final strip Point stripTopLeft = new Point(posLeft, 0); Point stripBottomRight = new Point(posRight, binaryStrip.rows()); return new Rect(stripTopLeft, stripBottomRight); }
From source file:org.akvo.caddisfly.sensor.colorimetry.strip.util.ResultUtil.java
License:Open Source License
@NonNull public static Mat concatenate(@NonNull Mat m1, @NonNull Mat m2) { int width = Math.max(m1.cols(), m2.cols()); int height = m1.rows() + m2.rows(); Mat result = new Mat(height, width, CvType.CV_8UC3, new Scalar(MAX_RGB_INT_VALUE, MAX_RGB_INT_VALUE, MAX_RGB_INT_VALUE)); // rect works with x, y, width, height Rect roi1 = new Rect(0, 0, m1.cols(), m1.rows()); Mat roiMat1 = result.submat(roi1);/*from w ww. ja v a 2s.co m*/ m1.copyTo(roiMat1); Rect roi2 = new Rect(0, m1.rows(), m2.cols(), m2.rows()); Mat roiMat2 = result.submat(roi2); m2.copyTo(roiMat2); return result; }