Skip to content

Instantly share code, notes, and snippets.

@ben-manes
Created June 30, 2016 00:42
Show Gist options
  • Save ben-manes/4bfa34c6c3f2f1902ee91bf8eb7f44d2 to your computer and use it in GitHub Desktop.
Save ben-manes/4bfa34c6c3f2f1902ee91bf8eb7f44d2 to your computer and use it in GitHub Desktop.
JavaCV segfault
def arch = System.getProperty('os.arch').toLowerCase()
arch = (arch == 'amd64') ? 'x86_64' : arch
ext {
env = [
arch: arch,
os: System.getProperty('os.name').replaceAll(' ', '').toLowerCase(),
]
versions = [
javacv: '1.2',
opencv: '3.1.0',
]
libraries = [
opencv: [
"org.bytedeco:javacv:${versions.javacv}",
"org.bytedeco.javacpp-presets:opencv:${versions.opencv}-${versions.javacv}:${env.os}-${env.arch}",
],
]
}
/* Copyright 2016 LoadDocs */
package co.loaddocs.service.document.upload;
import static org.bytedeco.javacpp.opencv_core.CV_32F;
import static org.bytedeco.javacpp.opencv_imgcodecs.IMREAD_GRAYSCALE;
import static org.bytedeco.javacpp.opencv_imgcodecs.cvLoadImage;
import static org.bytedeco.javacpp.opencv_imgcodecs.imread;
import static org.bytedeco.javacpp.opencv_imgcodecs.imwrite;
import static org.bytedeco.javacpp.opencv_imgproc.warpPerspective;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.math.RoundingMode;
import java.nio.file.Path;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.bytedeco.javacpp.opencv_core.CvMat;
import org.bytedeco.javacpp.opencv_core.IplImage;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_core.MatExpr;
import org.bytedeco.javacpp.opencv_core.Size;
import org.bytedeco.javacv.JavaCV;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Stopwatch;
import com.google.common.math.DoubleMath;
import co.loaddocs.service.generated.json.Contour;
import net.coobird.thumbnailator.Thumbnails;
/**
* @author ben@loaddocs.co (Ben Manes)
*/
@SuppressWarnings("deprecation")
public final class ImageTransforms {
private static final Logger logger = LoggerFactory.getLogger(ImageTransforms.class);
private static final int MAX_HEIGHT = 1650;
private static final int MAX_WIDTH = 1650;
public static final String FORMAT = "jpg";
private ImageTransforms() {}
/**
* Creates a PDF with a page per image.
*
* @param images the paths to the image files
* @param output the file path to the destination pdf
*/
public static void createPdf(List<Path> images, Path output) {
Stopwatch stopwatch = Stopwatch.createStarted();
try (PDDocument pdf = new PDDocument()) {
for (Path image : images) {
PDPage page = new PDPage();
pdf.addPage(page);
PDImageXObject pdfImage = PDImageXObject.createFromFileByExtension(image.toFile(), pdf);
try (PDPageContentStream contents = new PDPageContentStream(pdf, page)) {
page.setMediaBox(new PDRectangle(pdfImage.getWidth(), pdfImage.getHeight()));
contents.drawImage(pdfImage, 0, 0, page.getBBox().getWidth(), page.getBBox().getHeight());
}
}
pdf.save(output.toFile());
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
logger.info("Created PDF in {}", stopwatch);
}
}
/**
* Generates a scaled version of the source image.
*
* @param input the image to scale
* @param prefix the output image's prefix
* @param scale the scaling factor (0.0 - 1.0)
* @return the path to the output image
*/
public static Path scaleImage(Path input, String prefix, double scale) {
try {
Stopwatch stopwatch = Stopwatch.createStarted();
Path output = input.getParent().resolve(
String.format("%s_s%d.%s", prefix, (int) (100 * scale), FORMAT));
Thumbnails.Builder<File> builder = Thumbnails.of(input.toFile());
if (scale == 1.0) {
builder.size(MAX_WIDTH, MAX_HEIGHT);
} else {
builder.scale(scale);
}
builder.outputFormat(FORMAT).toFile(output.toFile());
logger.info("Scaled image {} in {}", output.getFileName(), stopwatch);
return output;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* Performs a gray scale transformation.
*
* @param input the file path to the source image
* @param output the file path to the destination image
*/
public static void grayScale(Path input, Path output) {
Stopwatch stopwatch = Stopwatch.createStarted();
try (Mat image = imread(input.toString(), IMREAD_GRAYSCALE)) {
imwrite(output.toString(), image);
}
logger.info("Gray scaled image {} in {}", output.getFileName(), stopwatch);
}
/**
* Transforms an image to obtain the top-down, "birds eye view" based on the supplied reference
* points.
*
* @param input the file path to the source image
* @param output the file path to the destination image
* @param contour the rectangular reference points to warp
*/
public static void topDownView(Path input, Path output, Contour contour) {
Stopwatch stopwatch = Stopwatch.createStarted();
// http://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example
int maxWidth = maxWidth(contour);
int maxHeight = maxHeight(contour);
try (IplImage image = cvLoadImage(input.toString());
Mat imageMat = new Mat(image);
MatExpr matrixExpr = Mat.eye(3, 3, CV_32F);
Mat matrix = matrixExpr.asMat();
CvMat M = new CvMat(matrix);
Mat warpedMat = new Mat(4, 1, CV_32F);
Size size = new Size(maxWidth, maxHeight)) {
double[] corners = getCorners(contour);
double[] dimensions = getDimensions(maxWidth, maxHeight);
JavaCV.getPerspectiveTransform(corners, dimensions, M);
warpPerspective(imageMat, warpedMat, matrix, size);
imwrite(output.toString(), warpedMat);
}
logger.info("Warped image {} in {}", output.getFileName(), stopwatch);
}
private static double[] getCorners(Contour contour) {
return new double[] {
contour.getTopLeftX(), contour.getTopLeftY(),
contour.getTopRightX(), contour.getTopRightY(),
contour.getBottomRightX(), contour.getBottomRightY(),
contour.getBottomLeftX(), contour.getBottomLeftY()
};
}
private static double[] getDimensions(int maxWidth, int maxHeight) {
return new double[] {
0, 0,
maxWidth - 1, 0,
maxWidth - 1, maxHeight - 1,
0, maxHeight - 1
};
}
private static int maxWidth(Contour contour) {
int first = distance(contour.getBottomRightX(), contour.getBottomRightY(),
contour.getBottomLeftX(), contour.getBottomLeftY());
int second = distance(contour.getTopRightX(), contour.getTopRightY(),
contour.getTopLeftX(), contour.getTopLeftY());
return Math.max(first, second);
}
private static int maxHeight(Contour contour) {
int first = distance(contour.getTopRightX(), contour.getTopRightY(),
contour.getBottomRightX(), contour.getBottomRightY());
int second = distance(contour.getTopLeftX(), contour.getTopLeftY(),
contour.getBottomLeftX(), contour.getBottomLeftY());
return Math.max(first, second);
}
private static int distance(int startX, int startY, int endX, int endY) {
double distance = Math.sqrt(Math.pow(startX - endX, 2) + Math.pow(startY - endY, 2));
return DoubleMath.roundToInt(distance, RoundingMode.UP);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment