/******************************************************************************* * Copyright (c) 2016 Weasis Team and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nicolas Roduit - initial API and implementation *******************************************************************************/ package org.weasis.core.api.image.util; import java.io.Serializable; import javax.media.jai.KernelJAI; import org.weasis.core.api.Messages; import org.weasis.core.api.gui.util.MathUtil; public class KernelData implements Serializable { private static final long serialVersionUID = 5877650534432337573L; public static final KernelData NONE = new KernelData(Messages.getString("KernelData.0"), false, 1, 1, new float[] { 1.0F }); //$NON-NLS-1$ public static final KernelData MEAN = new KernelData(Messages.getString("KernelData.1"), false, 3, 3, 1, 1, new float[] { 1.0F, 1.0F, //$NON-NLS-1$ 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, }, 9); public static final KernelData BLUR = new KernelData(Messages.getString("KernelData.2"), false, 3, 3, 1, 1, new float[] { 0.0F, 1.0F, //$NON-NLS-1$ 0.0F, 1.0F, 4.0F, 1.0F, 0.0F, 1.0F, 0.0F }, 8); public static final KernelData BLURMORE = new KernelData(Messages.getString("KernelData.3"), false, 3, 3, 1, 1, new float[] { 1.0F, //$NON-NLS-1$ 2.0F, 1.0F, 2.0F, 2.0F, 2.0F, 1.0F, 2.0F, 1.0F }, 14); public static final KernelData SHARPEN = new KernelData(Messages.getString("KernelData.4"), false, 3, 3, 1, 1, new float[] { 0.0F, //$NON-NLS-1$ -1.0F, 0.0F, -1.0F, 8.0F, -1.0F, 0.0F, -1.0F, 0.0F }, 4); public static final KernelData SHARPENMORE = new KernelData(Messages.getString("KernelData.5"), false, 3, 3, 1, 1, new float[] { //$NON-NLS-1$ -1.0F, -1.0F, -1.0F, -1.0F, 12.0F, -1.0F, -1.0F, -1.0F, -1.0F }, 4); public static final KernelData DEFOCUS = new KernelData(Messages.getString("KernelData.6"), false, 3, 3, new float[] { 1.0F, 1.0F, //$NON-NLS-1$ 1.0F, 1.0F, -7.0F, 1.0F, 1.0F, 1.0F, 1.0F }); public static final KernelData EDGE1 = new KernelData(Messages.getString("KernelData.7"), false, 3, 3, new float[] { 0.0F, //$NON-NLS-1$ -1.0F, 0.0F, -1.0F, 4.0F, -1.0F, 0.0F, -1.0F, 0.0F }); public static final KernelData EDGE2 = new KernelData(Messages.getString("KernelData.8"), false, 3, 3, new float[] { -1.0F, //$NON-NLS-1$ -1.0F, -1.0F, -1.0F, 8.0F, -1.0F, -1.0F, -1.0F, -1.0F }); public static final KernelData STRONGEDGE = new KernelData(Messages.getString("KernelData.9"), false, 5, 5, //$NON-NLS-1$ new float[] { -2.0F, -2.0F, -2.0F, -2.0F, -2.0F, -2.0F, -3.0F, -3.0F, -3.0F, -2.0F, -2.0F, -3.0F, 53.0F, -3.0F, -2.0F, -2.0F, -3.0F, -3.0F, -3.0F, -2.0F, -2.0F, -2.0F, -2.0F, -2.0F, -2.0F }); public static final KernelData OUTLINE = new KernelData(Messages.getString("KernelData.10"), false, 5, 5, //$NON-NLS-1$ new float[] { 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.0F, -16.0F, 0.0F, 1.0F, 1.0F, 0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F }); public static final KernelData EMBOSS = new KernelData(Messages.getString("KernelData.11"), false, 3, 3, new float[] { -5.0F, 0.0F, //$NON-NLS-1$ 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F, 5.0F }); public static final KernelData GAUSSIAN3 = gaussianKernel(Messages.getString("KernelData.12"), 3, 3); //$NON-NLS-1$ public static final KernelData GAUSSIAN5 = gaussianKernel(Messages.getString("KernelData.13"), 5, 5); //$NON-NLS-1$ public static final KernelData GAUSSIAN7 = gaussianKernel(Messages.getString("KernelData.14"), 7, 7); //$NON-NLS-1$ public static final KernelData GAUSSIAN9 = gaussianKernel(Messages.getString("KernelData.15"), 9, 9); //$NON-NLS-1$ public static final KernelData GAUSSIAN23 = gaussianKernel2(Messages.getString("KernelData.16"), 3); //$NON-NLS-1$ public static final KernelData GAUSSIAN25 = gaussianKernel2(Messages.getString("KernelData.17"), 5); //$NON-NLS-1$ public static final KernelData GAUSSIAN27 = gaussianKernel2(Messages.getString("KernelData.18"), 7); //$NON-NLS-1$ /** The type of the kernel. */ private boolean morphologicalFilter; /** The name of the kernel. */ private String name; /** The width of the kernel. */ private int width; /** The height of the kernel. */ private int height; /** The X coordinate of the key element. */ private int xOrigin; /** The Y coordinate of the key element. */ private int yOrigin; /** The divisior of the kernel values. */ private int divisor; /** The kernel data. */ private float[] data = null; public KernelData(String name, boolean morphologicalFilter, int width, int height, int xOrigin, int yOrigin, float[] data, int divisor) { this.name = name; this.morphologicalFilter = morphologicalFilter; this.width = width; this.height = height; setXOrigin(xOrigin); setYOrigin(yOrigin); this.divisor = divisor; this.data = divideKernel(data); } public KernelData(String name, boolean morphologicalFilter, int width, int height, float[] data) { this(name, morphologicalFilter, width, height, width / 2, height / 2, data, 1); } public float[] getData() { return data; } private float[] divideKernel(float[] data) { if (data == null) { return new float[width * height]; } if (divisor == 0) { divisor = 1; } if (divisor == 1) { return data; } float div = divisor; for (int i = 0; i < data.length; i++) { data[i] /= div; } return data; } public int getDivisor() { return divisor; } public int getHeight() { return height; } public String getName() { return name; } @Override public String toString() { return name; } public int getWidth() { return width; } public int getXOrigin() { return xOrigin; } public int getYOrigin() { return yOrigin; } public boolean isMorphologicalFilter() { return morphologicalFilter; } public boolean setYOrigin(int yOrigin) { if (yOrigin >= height || yOrigin < 0) { this.yOrigin = height / 2; return false; } this.yOrigin = yOrigin; return true; } public boolean setXOrigin(int xOrigin) { if (xOrigin >= width || xOrigin < 0) { this.xOrigin = width / 2; return false; } this.xOrigin = xOrigin; return true; } public void setWidth(int width) { this.width = width; } public void setName(String name) { this.name = name; } public void setHeight(int height) { this.height = height; } public void setDivisor(int divisor) { this.divisor = divisor; } public KernelJAI getKernelJAI() { if (data == null) { return new KernelJAI(1, 1, 0, 0, new float[] { 1.0F }); } else { return new KernelJAI(width, height, xOrigin, yOrigin, data); } } public static KernelData[] getAllFilters() { return new KernelData[] { NONE, MEAN, BLUR, BLURMORE, SHARPEN, SHARPENMORE, DEFOCUS, EDGE1, EDGE2, STRONGEDGE, OUTLINE, EMBOSS, GAUSSIAN3, GAUSSIAN5, GAUSSIAN7, GAUSSIAN9, GAUSSIAN23, GAUSSIAN25, GAUSSIAN27 }; } public static final KernelData makeGaussianKernel(String name, int radius) { int diameter = 2 * radius + 1; float invrsq = 1.0F / (radius * radius); float[] gaussianData = new float[diameter * diameter]; float sum = 0.0F; for (int i = 0; i < diameter; i++) { float d = i - (float) radius; float val = (float) Math.exp(-d * d * invrsq); gaussianData[i] = val; sum += val; } // Normalize float invsum = 1.0F / sum; for (int i = 0; i < diameter; i++) { gaussianData[i] *= invsum; } for (int i = diameter; i < gaussianData.length; i++) { gaussianData[i] = invsum; } return new KernelData(name, false, diameter, diameter, gaussianData); } public static int sign(float x) { if (x < 0.0F) { return -1 * (int) (-x + 0.5F); } else { return (int) (x + 0.5F); } } public static final KernelData gaussianKernel(String name, int nx, int ny) { int x = nx; int y = ny; if (x % 2 == 0) { x++; } if (y % 2 == 0) { y++; } float sigmax = (x - 1) / 6F; float sigmay = (y - 1) / 6F; return gaussianKernel(name, sigmax, sigmay); } public static final KernelData gaussianKernel(String name, float sigmax, float sigmay) { int nx = sign(6F * sigmax); int ny = sign(6F * sigmay); if (nx % 2 == 0) { nx++; } if (ny % 2 == 0) { ny++; } float[] gaussKernel = new float[nx * ny]; float scale = 0.0F; float sigmaX = MathUtil.isEqualToZero(sigmax) ? 1E-005F : sigmax; float sigmaY = MathUtil.isEqualToZero(sigmay) ? 1E-005F : sigmay; for (int j = 0; j < ny; j++) { float locy = j - (ny - 1) / 2.F; for (int i = 0; i < nx; i++) { float locx = i - (nx - 1) / 2.F; gaussKernel[j * nx + i] = (float) Math.exp(-0.5F * ((locx * locx) / (sigmaX * sigmaX) + (locy * locy) / (sigmaY * sigmaY))); scale += gaussKernel[j * nx + i]; } } for (int i = 0; i < gaussKernel.length; i++) { gaussKernel[i] /= scale; } return new KernelData(name, false, nx, ny, gaussKernel); } public static final KernelData gaussianKernel2(String name, int n) { float[] gaussKernel = new float[n * n]; float sigma = (n - 1) / 6F; float scale = 0.0F; for (int i = 0; i < n; i++) { float locy = i - (n - 1) / 2.F; for (int j = 0; j < n; j++) { float locx = j - (n - 1) / 2.F; float dist = (float) Math.sqrt(locy * locy + locx * locx); gaussKernel[j * n + i] = (-dist / (sigma * sigma)) * (float) Math.exp((-dist * dist) / (2.0F * sigma * sigma)); scale += gaussKernel[j * n + i]; } } for (int i = 0; i < gaussKernel.length; i++) { gaussKernel[i] /= scale; } return new KernelData(name, false, n, n, gaussKernel); } }