net.sourceforge.lept4j.util.LeptUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lept4j Show documentation
Show all versions of lept4j Show documentation
# Lept4J
## Description:
A Java JNA wrapper for Leptonica Image Processing library.
Lept4J is released and distributed under the Apache License, v2.0.
/*
* Copyright 2015 Quan Nguyen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.lept4j.util;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Iterator;
import java.util.Locale;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageOutputStream;
import com.github.jaiimageio.plugins.tiff.TIFFImageWriteParam;
import com.sun.jna.ptr.PointerByReference;
import com.ochafik.lang.jnaerator.runtime.NativeSize;
import com.ochafik.lang.jnaerator.runtime.NativeSizeByReference;
import com.sun.jna.Structure;
import net.sourceforge.lept4j.*;
import static net.sourceforge.lept4j.ILeptonica.IFF_TIFF;
//import org.opencv.core.Mat;
//import org.opencv.core.MatOfByte;
//import org.opencv.imgcodecs.Imgcodecs;
/**
* Various utility methods for Leptonica.
*
*/
public class LeptUtils {
final static String JAI_IMAGE_WRITER_MESSAGE = "Need to install JAI Image I/O package.\nhttps://github.com/jai-imageio/jai-imageio-core";
final static String TIFF_FORMAT = "tiff";
final static float deg2rad = (float) (3.14159 / 180.);
/**
* Converts Leptonica Pix
to BufferedImage
.
*
* @param pix source pix
* @return BufferedImage output image
* @throws IOException
*/
public static BufferedImage convertPixToImage(Pix pix) throws IOException {
PointerByReference pdata = new PointerByReference();
NativeSizeByReference psize = new NativeSizeByReference();
int format = IFF_TIFF;
Leptonica1.pixWriteMem(pdata, psize, pix, format);
byte[] b = pdata.getValue().getByteArray(0, psize.getValue().intValue());
InputStream in = new ByteArrayInputStream(b);
BufferedImage bi = ImageIO.read(in);
in.close();
Leptonica1.lept_free(pdata.getValue());
return bi;
}
/**
* Converts BufferedImage
to Leptonica Pix
.
*
* @param image source image
* @return Pix output pix
* @throws IOException
*/
public static Pix convertImageToPix(BufferedImage image) throws IOException {
ByteBuffer buff = getImageByteBuffer(image);
Pix pix = Leptonica1.pixReadMem(buff, new NativeSize(buff.capacity()));
return pix;
}
/**
* Removes horizontal lines from a grayscale image. The algorithm is based
* on Leptonica lineremoval.c
example.
*
* To remove vertical lines, rotate the image 90 degrees first, remove the
* horizontal lines, and rotate it back.
*
* @see
* line-removal
*
* @param pixs input pix
* @return pix with lines removed
*/
public static Pix removeLines(Pix pixs) {
float angle, conf;
Pix pix1, pix2, pix3, pix4, pix5;
Pix pix6, pix7, pix8, pix9;
/* threshold to binary, extracting much of the lines */
pix1 = Leptonica1.pixThresholdToBinary(pixs, 170);
/* find the skew angle and deskew using an interpolated
* rotator for anti-aliasing (to avoid jaggies) */
FloatBuffer pangle = FloatBuffer.allocate(1);
FloatBuffer pconf = FloatBuffer.allocate(1);
Leptonica1.pixFindSkew(pix1, pangle, pconf);
angle = pangle.get();
conf = pconf.get();
pix2 = Leptonica1.pixRotateAMGray(pixs, (float) (deg2rad * angle), (byte) 255);
/* extract the lines to be removed */
pix3 = Leptonica1.pixCloseGray(pix2, 51, 1);
/* solidify the lines to be removed */
pix4 = Leptonica1.pixErodeGray(pix3, 1, 5);
/* clean the background of those lines */
pix5 = Leptonica1.pixThresholdToValue(null, pix4, 210, 255);
pix6 = Leptonica1.pixThresholdToValue(null, pix5, 200, 0);
/* get paint-through mask for changed pixels */
pix7 = Leptonica1.pixThresholdToBinary(pix6, 210);
/* add the inverted, cleaned lines to orig. Because
* the background was cleaned, the inversion is 0,
* so when you add, it doesn't lighten those pixels.
* It only lightens (to white) the pixels in the lines! */
Leptonica1.pixInvert(pix6, pix6);
pix8 = Leptonica1.pixAddGray(null, pix2, pix6);
pix9 = Leptonica1.pixOpenGray(pix8, 1, 9);
Leptonica1.pixCombineMasked(pix8, pix9, pix7);
// resource cleanup
disposePix(pix1);
disposePix(pix2);
disposePix(pix3);
disposePix(pix4);
disposePix(pix5);
disposePix(pix6);
disposePix(pix7);
disposePix(pix9);
return pix8;
}
/**
* HMT (with just misses) for speckle up to 2x2
* "oooo"
*"oC o"
*"o o"
*"oooo"
*/
public static final String SEL_STR2 = "oooooC oo ooooo";
/**
* HMT (with just misses) for speckle up to 3x3
* "ooooo"
*"oC o"
*"o o"
*"o o"
*"ooooo"
*/
public static final String SEL_STR3 = "ooooooC oo oo oooooo";
/**
* Reduces speckle noise in image. The algorithm is based on Leptonica
* speckle_reg.c
example demonstrating morphological method of
* removing speckle.
*
* @param pixs input pix
* @param selStr hit-miss sels in 2D layout; SEL_STR2 and SEL_STR3 are
* predefined values
* @param selSize 2 for 2x2, 3 for 3x3
* @return pix with speckle removed
*/
public static Pix despeckle(Pix pixs, String selStr, int selSize) {
Pix pix1, pix2, pix3;
Pix pix4, pix5, pix6;
Sel sel1, sel2;
/* Normalize for rapidly varying background */
pix1 = Leptonica1.pixBackgroundNormFlex(pixs, 7, 7, 1, 1, 10);
/* Remove the background */
pix2 = Leptonica1.pixGammaTRCMasked(null, pix1, null, 1.0f, 100, 175);
/* Binarize */
pix3 = Leptonica1.pixThresholdToBinary(pix2, 180);
/* Remove the speckle noise up to selSize x selSize */
sel1 = Leptonica1.selCreateFromString(selStr, selSize + 2, selSize + 2, "speckle" + selSize);
pix4 = Leptonica1.pixHMT(null, pix3, sel1.getPointer());
sel2 = Leptonica1.selCreateBrick(selSize, selSize, 0, 0, ILeptonica.SEL_HIT);
pix5 = Leptonica1.pixDilate(null, pix4, sel2.getPointer());
pix6 = Leptonica1.pixSubtract(null, pix3, pix5);
LeptUtils.dispose(sel1);
LeptUtils.dispose(sel2);
LeptUtils.dispose(pix1);
LeptUtils.dispose(pix2);
LeptUtils.dispose(pix3);
LeptUtils.dispose(pix4);
LeptUtils.dispose(pix5);
return pix6;
}
/**
* Disposes of Pix resource.
*
* @param pix
*/
public static void disposePix(Pix pix) {
if (pix == null) {
return;
}
PointerByReference pRef = new PointerByReference();
pRef.setValue(pix.getPointer());
Leptonica1.pixDestroy(pRef);
}
/**
* Disposes of Leptonica native resource.
*
* @param resource A Leptonica object, such as Pix
,
* Pixa
, Box
, Boxa
,
* PixColormap
, etc.
*/
public static void dispose(Structure resource) {
if (resource == null) {
return;
}
PointerByReference pRef = new PointerByReference();
pRef.setValue(resource.getPointer());
if (resource instanceof Pix) {
Leptonica1.pixDestroy(pRef);
} else if (resource instanceof Pixa) {
Leptonica1.pixaDestroy(pRef);
} else if (resource instanceof Box) {
Leptonica1.boxDestroy(pRef);
} else if (resource instanceof Boxa) {
Leptonica1.boxaDestroy(pRef);
} else if (resource instanceof L_Bmf) {
Leptonica1.bmfDestroy(pRef);
} else if (resource instanceof L_ByteBuffer) {
Leptonica1.bbufferDestroy(pRef);
} else if (resource instanceof Boxaa) {
Leptonica1.boxaaDestroy(pRef);
} else if (resource instanceof L_Bytea) {
Leptonica1.l_byteaDestroy(pRef);
} else if (resource instanceof CCBorda) {
Leptonica1.ccbaDestroy(pRef);
} else if (resource instanceof CCBord) {
Leptonica1.ccbDestroy(pRef);
} else if (resource instanceof PixColormap) {
Leptonica1.pixcmapDestroy(pRef);
} else if (resource instanceof L_Dewarp) {
Leptonica1.dewarpDestroy(pRef);
} else if (resource instanceof L_Dewarpa) {
Leptonica1.dewarpaDestroy(pRef);
} else if (resource instanceof L_Dna) {
Leptonica1.l_dnaDestroy(pRef);
} else if (resource instanceof L_Dnaa) {
Leptonica1.l_dnaaDestroy(pRef);
} else if (resource instanceof L_DnaHash) {
Leptonica1.l_dnaHashDestroy(pRef);
} else if (resource instanceof FPix) {
Leptonica1.fpixDestroy(pRef);
} else if (resource instanceof FPixa) {
Leptonica1.fpixaDestroy(pRef);
} else if (resource instanceof DPix) {
Leptonica1.dpixDestroy(pRef);
} else if (resource instanceof GPlot) {
Leptonica1.gplotDestroy(pRef);
} else if (resource instanceof JbClasser) {
Leptonica1.jbClasserDestroy(pRef);
} else if (resource instanceof JbData) {
Leptonica1.jbDataDestroy(pRef);
} else if (resource instanceof L_Kernel) {
Leptonica1.kernelDestroy(pRef);
} else if (resource instanceof Numa) {
Leptonica1.numaDestroy(pRef);
} else if (resource instanceof Numaa) {
Leptonica1.numaaDestroy(pRef);
} else if (resource instanceof Pixaa) {
Leptonica1.pixaaDestroy(pRef);
} else if (resource instanceof Pixacc) {
Leptonica1.pixaccDestroy(pRef);
} else if (resource instanceof PixComp) {
Leptonica1.pixcompDestroy(pRef);
} else if (resource instanceof PixaComp) {
Leptonica1.pixacompDestroy(pRef);
} else if (resource instanceof PixTiling) {
Leptonica1.pixTilingDestroy(pRef);
} else if (resource instanceof Pta) {
Leptonica1.ptaDestroy(pRef);
} else if (resource instanceof Ptaa) {
Leptonica1.ptaaDestroy(pRef);
} else if (resource instanceof L_Recog) {
Leptonica1.recogDestroy(pRef);
} else if (resource instanceof Sarray) {
Leptonica1.sarrayDestroy(pRef);
} else if (resource instanceof Sel) {
Leptonica1.selDestroy(pRef);
} else if (resource instanceof Sela) {
Leptonica1.selaDestroy(pRef);
} else if (resource instanceof L_Sudoku) {
Leptonica1.sudokuDestroy(pRef);
} else if (resource instanceof L_WShed) {
Leptonica1.wshedDestroy(pRef);
} else if (resource instanceof DoubleLinkedList) {
Leptonica1.listDestroy(pRef);
} else if (resource instanceof L_Rbtree) {
Leptonica1.l_rbtreeDestroy(pRef);
} else {
throw new RuntimeException("Not supported.");
}
}
/**
* Gets image data of an RenderedImage
object.
*
* @param image an RenderedImage
object
* @return a byte buffer of image data
* @throws IOException
*/
static ByteBuffer getImageByteBuffer(RenderedImage image) throws IOException {
//Set up the writeParam
TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam(Locale.US);
tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);
//Get tif writer and set output to file
Iterator writers = ImageIO.getImageWritersByFormatName(TIFF_FORMAT);
if (!writers.hasNext()) {
throw new RuntimeException(JAI_IMAGE_WRITER_MESSAGE);
}
ImageWriter writer = writers.next();
//Get the stream metadata
IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(tiffWriteParam);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream);
writer.setOutput(ios);
writer.write(streamMetadata, new IIOImage(image, null, null), tiffWriteParam);
// writer.write(image);
writer.dispose();
ios.seek(0);
byte[] b = new byte[(int) ios.length()];
ios.read(b);
ios.close();
ByteBuffer buf = ByteBuffer.allocateDirect(b.length);
buf.order(ByteOrder.nativeOrder());
buf.put(b);
buf.flip();
return buf;
}
// /**
// * Converts OpenCV Mat to Leptonica Pix.
// *
// * @param mat source mat
// * @return output pix
// */
// public static Pix convertMatToPix(Mat mat) {
// MatOfByte bytes = new MatOfByte();
// Imgcodecs.imencode(".tif", mat, bytes);
// ByteBuffer buff = ByteBuffer.wrap(bytes.toArray());
// return Leptonica1.pixReadMem(buff, new NativeSize(buff.capacity()));
// }
//
// /**
// * Converts Leptonica Pix to OpenCV Mat.
// * @param pix source pix
// * @return output mat
// */
// public static Mat convertPixToMat(Pix pix) {
// PointerByReference pdata = new PointerByReference();
// NativeSizeByReference psize = new NativeSizeByReference();
// Leptonica1.pixWriteMem(pdata, psize, pix, ILeptonica.IFF_TIFF);
// byte[] b = pdata.getValue().getByteArray(0, psize.getValue().intValue());
// Leptonica1.lept_free(pdata.getValue());
// return Imgcodecs.imdecode(new MatOfByte(b), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
// }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy