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

net.sourceforge.lept4j.util.LeptUtils Maven / Gradle / Ivy

Go to download

# Lept4J ## Description: A Java JNA wrapper for Leptonica Image Processing library. Lept4J is released and distributed under the Apache License, v2.0.

There is a newer version: 1.20.0
Show newest version
/*
 * 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