Created
June 30, 2016 00:42
-
-
Save ben-manes/4bfa34c6c3f2f1902ee91bf8eb7f44d2 to your computer and use it in GitHub Desktop.
JavaCV segfault
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}", | |
], | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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 [email protected] (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