package plugins.nherve.toolbox.image.feature.lbp;
import icy.image.IcyBufferedImage;
import java.awt.Shape;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import plugins.nherve.toolbox.Pair;
import plugins.nherve.toolbox.image.feature.SegmentableIcyBufferedImage;
import plugins.nherve.toolbox.image.feature.SupportRegion;
import plugins.nherve.toolbox.image.feature.descriptor.GlobalAndLocalDescriptor;
import plugins.nherve.toolbox.image.feature.region.FullImageSupportRegion;
import plugins.nherve.toolbox.image.feature.region.IcyPixel;
import plugins.nherve.toolbox.image.feature.signature.SignatureException;
import plugins.nherve.toolbox.image.feature.signature.DefaultVectorSignature;
import plugins.nherve.toolbox.image.feature.signature.VectorSignatureConcatenator;
import plugins.nherve.toolbox.image.toolboxes.ColorSpaceTools;
import plugins.nherve.toolbox.image.toolboxes.ImageTools;
import plugins.nherve.toolbox.image.toolboxes.SomeImageTools;
public class LocalBinaryPattern extends GlobalAndLocalDescriptor<SegmentableIcyBufferedImage, DefaultVectorSignature> {
public final static int BINARY_ENCODING = 1;
public final static int TERNARY_ENCODING = 2;
private LBPToolbox tbx;
private int w;
private boolean fuzzy;
private boolean fuzzyAllChannels;
private boolean fuzzyCross;
private boolean fuzzyOnlyCross;
private boolean ri;
private int fuzzyChannel;
private int fuzzyColorSpace;
private LBPToolbox pptbx;
private Map<SegmentableIcyBufferedImage, IcyBufferedImage[]> cachePrecomputedLBP;
private Map<SegmentableIcyBufferedImage, List<Pair<Integer, Integer>>> cachePairs;
private Map<SegmentableIcyBufferedImage, Map<Integer, IcyBufferedImage>> cacheGrays;
public LocalBinaryPattern(int p, double r, int w, boolean ri, boolean uniform, int v, int encoding, boolean in, boolean display) {
super(display);
fuzzy = false;
fuzzyAllChannels = false;
fuzzyCross = false;
fuzzyOnlyCross = false;
fuzzyChannel = 0;
fuzzyColorSpace = ColorSpaceTools.RGB_TO_I1H2H3;
this.w = w;
this.ri = ri;
tbx = new LBPToolbox(p, r, ri, uniform, v, encoding, in, display);
cachePrecomputedLBP = new HashMap<SegmentableIcyBufferedImage, IcyBufferedImage[]>();
cacheGrays = new HashMap<SegmentableIcyBufferedImage, Map<Integer,IcyBufferedImage>>();
cachePairs = new HashMap<SegmentableIcyBufferedImage, List<Pair<Integer,Integer>>>();
}
public LocalBinaryPattern(int p, double r, int w, boolean ri, boolean uniform, int v, boolean in, boolean display) {
this(p, r, w, ri, uniform, v, BINARY_ENCODING, in, display);
}
public LocalBinaryPattern(int p, double r, boolean ri, boolean uniform, int v, int encoding, boolean in, boolean display) {
this(p, r, 0, ri, uniform, v, encoding, in, display);
}
public LocalBinaryPattern(int p, double r, boolean ri, boolean uniform, int v, boolean in, boolean display) {
this(p, r, 0, ri, uniform, v, BINARY_ENCODING, in, display);
}
public LocalBinaryPattern(int p, double r, int ft, double param, boolean display) {
this(p, r, ft, param, display, true);
}
public LocalBinaryPattern(int p, double r, int ft, double t, boolean display, boolean riu) {
this(p, r, 0, false, false, 1, true, display);
this.ri = riu;
tbx.setFuzzyFunction(ft, t);
fuzzy = true;
pptbx = new LBPToolbox(p, r, true, true, 1, BINARY_ENCODING, true, display);
}
public LocalBinaryPattern(int p, double r, int ft, double t, boolean display, boolean riu, int v, boolean in) {
this(p, r, 0, false, false, v, in, display);
this.ri = riu;
tbx.setFuzzyFunction(ft, t);
fuzzy = true;
pptbx = new LBPToolbox(p, r, true, true, v, BINARY_ENCODING, in, display);
}
public DefaultVectorSignature extractLocalSignature(IcyBufferedImage precomputedLBP, SupportRegion<IcyPixel> reg) throws SignatureException {
DefaultVectorSignature sig = getEmptySignature(tbx.getTernarySingleSignatureSize());
int[] loc = precomputedLBP.getDataXYAsInt(0);
if (reg instanceof FullImageSupportRegion) {
for (int x = 0; x < loc.length; x++) {
sig.addTo(loc[x], 1);
}
} else {
int imgW = precomputedLBP.getWidth();
int imgH = precomputedLBP.getHeight();
IcyPixel px = reg.getCenter();
int cx = (int) px.x;
int cy = (int) px.y;
int x1 = Math.max(cx - w, 0);
int x2 = Math.min(cx + w, imgW - 1);
int y1 = Math.max(cy - w, 0);
int y2 = Math.min(cy + w, imgH - 1);
int off = 0;
for (int y = y1; y <= y2; y++) {
off = y * imgW + x1;
for (int x = x1; x <= x2; x++) {
sig.addTo(loc[off], 1);
off++;
}
}
}
sig.normalizeSumToOne(true);
return sig;
}
@Override
public DefaultVectorSignature extractLocalSignature(SegmentableIcyBufferedImage img, SupportRegion<IcyPixel> reg) throws SignatureException {
if (fuzzy) {
int off = 0;
List<Pair<Integer, Integer>> pairs = null;
Map<Integer, IcyBufferedImage> grays = null;
synchronized (cacheGrays) {
grays = cacheGrays.get(img);
}
if (grays == null) {
throw new SignatureException("PreProcess not launched for current image (" + img.getName() + ")");
}
synchronized (cachePairs) {
pairs = cachePairs.get(img);
}
if (pairs == null) {
throw new SignatureException("PreProcess not launched for current image (" + img.getName() + ")");
}
// TODO EN COURS DE TEST 2
int finalSigSize = 0;
if (ri) {
finalSigSize = pptbx.getSignatureSize() * pairs.size();
} else {
finalSigSize = tbx.getSignatureSize() * pairs.size();
}
DefaultVectorSignature sigf = getEmptySignature(finalSigSize);
for (Pair<Integer, Integer> p : pairs) {
IcyBufferedImage center = grays.get(p.first);
IcyBufferedImage neighbours = grays.get(p.second);
double[] precomputedLBP = null;
if (reg instanceof FullImageSupportRegion) {
precomputedLBP = tbx.computeFuzzyFullImage(center, neighbours);
} else {
precomputedLBP = tbx.computeFuzzyRegion(center, neighbours, reg);
}
DefaultVectorSignature sig1 = getEmptySignature(precomputedLBP.length);
for (int i = 0; i < precomputedLBP.length; i++) {
sig1.set(i, precomputedLBP[i]);
}
// TODO EN COURS DE TEST 2
// TODO Revoir notamment la dimension finale du vecteur
if (ri) {
DefaultVectorSignature sig2 = getEmptySignature(pptbx.getSignatureSize());
for (int d = 0; d < sig1.getSize(); d++) {
sig2.addTo((int) pptbx.getRI(d), sig1.get(d));
}
sig2.normalizeSumToOne(true);
sig1 = sig2;
}
// ---
for (int d = 0; d < sig1.getSize(); d++) {
sigf.set(off + d, sig1.get(d));
}
off += sig1.getSize();
}
sigf.normalizeSumToOne(true);
// System.out.println(sigf.toString());
return sigf;
} else {
IcyBufferedImage[] precomputedLBP = null;
synchronized (cachePrecomputedLBP) {
precomputedLBP = cachePrecomputedLBP.get(img);
}
if (precomputedLBP == null) {
throw new SignatureException("PreProcess not launched for current image (" + img.getName() + ")");
}
if (precomputedLBP.length > 1) {
VectorSignatureConcatenator concat = new VectorSignatureConcatenator(DefaultVectorSignature.DENSE_VECTOR_SIGNATURE, false);
for (IcyBufferedImage pre : precomputedLBP) {
concat.add(extractLocalSignature(pre, reg));
}
return concat.concatenate()[0];
} else {
return extractLocalSignature(precomputedLBP[0], reg);
}
}
}
@Override
public DefaultVectorSignature extractLocalSignature(SegmentableIcyBufferedImage img, Shape shape) throws SignatureException {
throw new SignatureException("LocalBinaryPattern::extractLocalSignature not implemented for shape");
}
@Override
public int getSignatureSize() {
if (fuzzyAllChannels) {
return tbx.getSignatureSize() * 3;
}
return tbx.getSignatureSize();
}
@Override
public void postProcess(SegmentableIcyBufferedImage img) throws SignatureException {
synchronized (cachePrecomputedLBP) {
cachePrecomputedLBP.remove(img);
}
synchronized (cacheGrays) {
cacheGrays.remove(img);
}
synchronized (cachePairs) {
cachePairs.remove(img);
}
}
@Override
public void preProcess(SegmentableIcyBufferedImage img) throws SignatureException {
if (fuzzy) {
int maxCanal = 0;
int minCanal = 0;
if (fuzzyAllChannels) {
minCanal = 0;
maxCanal = 2;
} else {
minCanal = fuzzyChannel;
maxCanal = fuzzyChannel;
}
List<Pair<Integer, Integer>> pairs = new ArrayList<Pair<Integer, Integer>>();
Map<Integer, IcyBufferedImage> grays = new HashMap<Integer, IcyBufferedImage>();
if (fuzzyCross) {
for (int c1 = minCanal; c1 <= maxCanal; c1++) {
for (int c2 = minCanal; c2 <= maxCanal; c2++) {
if (!fuzzyOnlyCross || (c1 != c2)) {
pairs.add(Pair.of(c1, c2));
}
}
}
} else {
for (int canal = minCanal; canal <= maxCanal; canal++) {
pairs.add(Pair.of(canal, canal));
}
}
for (int canal = minCanal; canal <= maxCanal; canal++) {
grays.put(canal, SomeImageTools.computeGrayScale(img.getImage(), fuzzyColorSpace, canal, 1));
}
synchronized (cacheGrays) {
cacheGrays.put(img, grays);
}
synchronized (cachePairs) {
cachePairs.put(img, pairs);
}
} else {
IcyBufferedImage gray = SomeImageTools.computeGrayScale(img.getImage(), 0, 1);
// TODO en cours de test1
/*
* if (tbx.getR() > 1) { ConvolutionKernel2D g =
* ConvolutionKernel2D.getGaussianFilter(Math.PI * tbx.getR() / (2 *
* tbx.getP())); double[] d = g.convolveIntensity(gray);
* gray.setDataXYAsDouble(0, d); gray.dataChanged(); }
*/
// ---
IcyBufferedImage[] precomputedLBP = null;
// if (fuzzy) {
// precomputedLBP = tbx.computeFuzzy(gray);
// } else {
precomputedLBP = tbx.compute(gray);
// }
synchronized (cachePrecomputedLBP) {
cachePrecomputedLBP.put(img, precomputedLBP);
}
}
}
@Override
public String toString() {
return "LBP " + tbx.toString();
}
@Override
public boolean needToLoadSegmentable() {
return true;
}
public LBPToolbox getTbx() {
return tbx;
}
public void setTernaryThreshold(double ternaryThreshold) {
tbx.setTernaryThreshold(ternaryThreshold);
}
public void setFuzzyAllChannels(boolean fuzzyAllChannels) {
this.fuzzyAllChannels = fuzzyAllChannels;
}
public void setFuzzyChannel(int fuzzyChannel) {
this.fuzzyChannel = fuzzyChannel;
}
public void setFuzzyColorSpace(int fuzzyColorSpace) {
this.fuzzyColorSpace = fuzzyColorSpace;
}
public void setFuzzyCross(boolean fuzzyCross) {
this.fuzzyCross = fuzzyCross;
}
public void setFuzzyOnlyCross(boolean fuzzyOnlyCross) {
this.fuzzyOnlyCross = fuzzyOnlyCross;
}
@Override
public void setLogEnabled(boolean display) {
super.setLogEnabled(display);
if (tbx != null) {
tbx.setLogEnabled(display);
}
if (pptbx != null) {
pptbx.setLogEnabled(display);
}
}
}