All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openimaj.image.processing.edges.CannyEdgeDetector2 Maven / Gradle / Ivy

/**
 * Copyright (c) 2011, The University of Southampton and the individual contributors.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *   * 	Redistributions of source code must retain the above copyright notice,
 * 	this list of conditions and the following disclaimer.
 *
 *   *	Redistributions in binary form must reproduce the above copyright notice,
 * 	this list of conditions and the following disclaimer in the documentation
 * 	and/or other materials provided with the distribution.
 *
 *   *	Neither the name of the University of Southampton nor the names of its
 * 	contributors may be used to endorse or promote products derived from this
 * 	software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.openimaj.image.processing.edges;

import org.openimaj.image.DisplayUtilities;
import org.openimaj.image.FImage;
import org.openimaj.image.analysis.algorithm.EdgeDirectionCoherenceVector;
import org.openimaj.image.processor.SinglebandImageProcessor;

/**
 * This implementation is deprecated and is only kept for backward-compatibility
 * of old {@link EdgeDirectionCoherenceVector} features. Use the
 * {@link CannyEdgeDetector} instead.
 * 

* This is an implementation of the canny edge detector that was found somewhere * out there on the web with no attribution. If this is your code and you don't * want it in OpenIMAJ, please let us know. * * @author David Dupplaw ([email protected]) */ @Deprecated public class CannyEdgeDetector2 implements SinglebandImageProcessor { private boolean complete; /** The threshold */ private int threshold = 128; /** The first hysteresis threshold */ private int hystThresh1 = 50; /** The second hysteresis threshold */ private int hystThresh2 = 230; /** The Guassian kernel size */ private int kernelSize = 15; final float ORIENT_SCALE = 40F; private int height; private int width; private int picsize; private float[] data; private int derivative_mag[]; private float magnitude[]; private float orientation[]; private FImage sourceImage; private FImage edgeImage; /** * Default constructor */ public CannyEdgeDetector2() { complete = false; } /** * @return Returns whether the processing has completed. */ public boolean isImageReady() { return complete; } /** * {@inheritDoc} * * @see org.openimaj.image.processor.ImageProcessor#processImage(org.openimaj.image.Image) */ @Override public void processImage(FImage image) { complete = false; final int widGaussianKernel = kernelSize; final int threshold = this.threshold; final int threshold1 = hystThresh1; final int threshold2 = hystThresh2; if (threshold < 0 || threshold > 255) { throw new IllegalArgumentException("The value of the threshold " + "is out of its valid range."); } if (widGaussianKernel < 3 || widGaussianKernel > 40) { throw new IllegalArgumentException("The value of the widGaussianKernel " + "is out of its valid range."); } width = image.getWidth(); height = image.getHeight(); picsize = width * height; sourceImage = image; data = new float[picsize]; magnitude = new float[picsize]; orientation = new float[picsize]; final float f = 1.0F; canny_core(f, widGaussianKernel); thresholding_tracker(threshold1, threshold2); for (int i = 0; i < picsize; i++) if (data[i] > threshold) data[i] = 1; else data[i] = -1; edgeImage = new FImage(data, width, height).normalise(); data = null; complete = true; image.internalAssign(edgeImage); } /** * Assumes the input is a one-dimensional representation of an image. * Displays the image. * * @param data * A one-dimensional representation of an image. */ protected void display(int[] data) { final FImage tmp = new FImage(width, height); for (int r = 0; r < height; r++) for (int c = 0; c < width; c++) tmp.pixels[r][c] = data[c + r * width] / 255f; DisplayUtilities.display(tmp); } /** * Assumes the input is a one-dimensional representation of an image. * Displays the image. * * @param data * A one-dimensional representation of an image. */ protected void display(float[] data) { final FImage tmp = new FImage(width, height); for (int r = 0; r < height; r++) for (int c = 0; c < width; c++) tmp.pixels[r][c] = data[c + r * width] / 255f; DisplayUtilities.display(tmp); } /** * @param f * @param i */ private void canny_core(float f, int i) { derivative_mag = new int[picsize]; final float af4[] = new float[i]; final float af5[] = new float[i]; final float af6[] = new float[i]; // data = image2pixels( sourceImage ); data = sourceImage.clone().multiply(255.0f).getFloatPixelVector(); int k4 = 0; do { if (k4 >= i) break; final float f1 = gaussian(k4, f); if (f1 <= 0.005F && k4 >= 2) break; final float f2 = gaussian(k4 - 0.5F, f); final float f3 = gaussian(k4 + 0.5F, f); final float f4 = gaussian(k4, f * 0.5F); af4[k4] = (f1 + f2 + f3) / 3F / (6.283185F * f * f); af5[k4] = f3 - f2; af6[k4] = 1.6F * f4 - f1; k4++; } while (true); final int j = k4; float af[] = new float[picsize]; float af1[] = new float[picsize]; int j1 = width - (j - 1); int l = width * (j - 1); int i1 = width * (height - (j - 1)); for (int l4 = j - 1; l4 < j1; l4++) { for (int l5 = l; l5 < i1; l5 += width) { final int k1 = l4 + l5; float f8 = data[k1] * af4[0]; float f10 = f8; int l6 = 1; int k7 = k1 - width; for (int i8 = k1 + width; l6 < j; i8 += width) { f8 += af4[l6] * (data[k7] + data[i8]); f10 += af4[l6] * (data[k1 - l6] + data[k1 + l6]); l6++; k7 -= width; } af[k1] = f8; af1[k1] = f10; } } float af2[] = new float[picsize]; for (int i5 = j - 1; i5 < j1; i5++) { for (int i6 = l; i6 < i1; i6 += width) { float f9 = 0.0F; final int l1 = i5 + i6; for (int i7 = 1; i7 < j; i7++) f9 += af5[i7] * (af[l1 - i7] - af[l1 + i7]); af2[l1] = f9; } } af = null; float af3[] = new float[picsize]; for (int j5 = k4; j5 < width - k4; j5++) { for (int j6 = l; j6 < i1; j6 += width) { float f11 = 0.0F; final int i2 = j5 + j6; int j7 = 1; for (int l7 = width; j7 < j; l7 += width) { f11 += af5[j7] * (af1[i2 - l7] - af1[i2 + l7]); j7++; } af3[i2] = f11; } } // display(af3); af1 = null; j1 = width - j; l = width * j; i1 = width * (height - j); for (int k5 = j; k5 < j1; k5++) { for (int k6 = l; k6 < i1; k6 += width) { final int j2 = k5 + k6; final int k2 = j2 - width; final int l2 = j2 + width; final int i3 = j2 - 1; final int j3 = j2 + 1; final int k3 = k2 - 1; final int l3 = k2 + 1; final int i4 = l2 - 1; final int j4 = l2 + 1; final float f6 = af2[j2]; final float f7 = af3[j2]; final float f12 = hypotenuse(f6, f7); final int k = (int) (f12 * 20D); derivative_mag[j2] = k >= 256 ? 255 : k; final float f13 = hypotenuse(af2[k2], af3[k2]); final float f14 = hypotenuse(af2[l2], af3[l2]); final float f15 = hypotenuse(af2[i3], af3[i3]); final float f16 = hypotenuse(af2[j3], af3[j3]); final float f18 = hypotenuse(af2[l3], af3[l3]); final float f20 = hypotenuse(af2[j4], af3[j4]); final float f19 = hypotenuse(af2[i4], af3[i4]); final float f17 = hypotenuse(af2[k3], af3[k3]); float f5; if (f6 * f7 <= 0 ? Math.abs(f6) >= Math.abs(f7) ? (f5 = Math.abs(f6 * f12)) >= Math.abs(f7 * f18 - (f6 + f7) * f16) && f5 > Math.abs(f7 * f19 - (f6 + f7) * f15) : ( f5 = Math.abs(f7 * f12)) >= Math.abs(f6 * f18 - (f7 + f6) * f13) && f5 > Math.abs(f6 * f19 - (f7 + f6) * f14) : Math.abs(f6) >= Math.abs(f7) ? (f5 = Math.abs(f6 * f12)) >= Math.abs(f7 * f20 + (f6 - f7) * f16) && f5 > Math.abs(f7 * f17 + (f6 - f7) * f15) : ( f5 = Math.abs(f7 * f12)) >= Math.abs(f6 * f20 + (f7 - f6) * f14) && f5 > Math.abs(f6 * f17 + (f7 - f6) * f13)) { magnitude[j2] = derivative_mag[j2]; orientation[j2] = (float) Math.toDegrees( Math.atan2(f7, f6)); } } } derivative_mag = null; af2 = null; af3 = null; } /** * If f and f1 are the shorter sides of a * triangle, calculates the hypotenuse of the triangle. * * @param f * short side of a triangle * @param f1 * short side of a triangle * @return The length of the hypotenuse. */ private float hypotenuse(float f, float f1) { if (f == 0.0F && f1 == 0.0F) return 0.0F; else return (float) Math.sqrt(f * f + f1 * f1); } private float gaussian(float f, float f1) { return (float) Math.exp((-f * f) / (2 * f1 * f1)); } private void thresholding_tracker(int i, int j) { for (int k = 0; k < picsize; k++) data[k] = 0; for (int l = 0; l < width; l++) { for (int i1 = 0; i1 < height; i1++) if (magnitude[l + width * i1] >= i) follow(l, i1, j); } } /** * @param i * @param j * @param k * @return */ private boolean follow(int i, int j, int k) { int j1 = i + 1; int k1 = i - 1; int l1 = j + 1; int i2 = j - 1; final int j2 = i + j * width; if (l1 >= height) l1 = height - 1; if (i2 < 0) i2 = 0; if (j1 >= width) j1 = width - 1; if (k1 < 0) k1 = 0; if (data[j2] == 0) { data[j2] = magnitude[j2]; boolean flag = false; int l = k1; do { if (l > j1) break; int i1 = i2; do { if (i1 > l1) break; final int k2 = l + i1 * width; if ((i1 != j || l != i) && magnitude[k2] >= k && follow(l, i1, k)) { flag = true; break; } i1++; } while (true); if (!flag) break; l++; } while (true); return true; } else { return false; } } /** * @param image */ public void setSourceImage(FImage image) { sourceImage = image; } /** * @return edgeImage */ public FImage getEdgeImage() { return edgeImage; } /** * @return magnitude */ public float[] getMagnitude() { return magnitude; } /** * @return orientation */ public float[] getOrientation() { return orientation; } /** * Get the threshold above which an edge pixel will be considered an edge. * * @return the threshold above which edge pixels will be considered edges. */ public int getThreshold() { return threshold; } /** * Get the threshold above which an edge pixel will be considered an edge. * * @param threshold * the threshold above which an edge pixel will be considered an * edge. */ public void setThreshold(int threshold) { this.threshold = threshold; } /** * Get the first hysteresis threshold. * * @return the first hysteresis threshold. */ public int getHystThresh1() { return hystThresh1; } /** * Set the fist hysteresis threshold. * * @param hystThresh1 * the threshold value */ public void setHystThresh1(int hystThresh1) { this.hystThresh1 = hystThresh1; } /** * Get the second hysteresis threshold. * * @return the second hysteresis threshold. */ public int getHystThresh2() { return hystThresh2; } /** * Set the second hysteresis threshold. * * @param hystThresh2 * the threshold value */ public void setHystThresh2(int hystThresh2) { this.hystThresh2 = hystThresh2; } /** * Get the kernel size being used. * * @return the kernel size being used for blurring */ public int getKernelSize() { return kernelSize; } /** * Set the kernel size to use. * * @param kernelSize * the size of the kernel to use for blurring. */ public void setKernelSize(int kernelSize) { this.kernelSize = kernelSize; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy