package com.drawbridge.dm;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import javax.swing.JOptionPane;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Rect;
import org.opencv.imgproc.Imgproc;
import com.drawbridge.jsengine.ast.Evaluator;
import com.drawbridge.paper.PaperPanel;
import com.drawbridge.utils.ASTModification;
import com.drawbridge.utils.CVUtils;
import com.drawbridge.utils.HandleBorder;
import com.drawbridge.utils.JSUtils;
import com.drawbridge.utils.Utils;
public class DMImageFactory
{
protected DMImageFactory() {
}
public static LinkedList<DMImage> decodeBufferedImage(BufferedImage image)
{
int cvType = 0;
int bufferedImageType = image.getType();
if (bufferedImageType == BufferedImage.TYPE_INT_BGR || bufferedImageType == BufferedImage.TYPE_3BYTE_BGR)
cvType = Imgproc.COLOR_BGR2HSV;
else if (bufferedImageType == BufferedImage.TYPE_INT_RGB)
cvType = Imgproc.COLOR_RGB2HSV;
else if (bufferedImageType == BufferedImage.TYPE_INT_ARGB)
throw new RuntimeException("Don't like ARGB");
else
{
throw new RuntimeException("Unexpected image type: " + bufferedImageType);
}
// Convert the image to a mat
Mat mat = CVUtils.getMatFromBufferedImage(image);
// Process the mat
Imgproc.cvtColor(mat, mat, cvType);
// Get V from HSV
ArrayList<Mat> list = new ArrayList<Mat>();
org.opencv.core.Core.split(mat, list);
Mat vMat = null;
if (list.size() == 3)
{
vMat = list.get(2);
}
else
{
throw new RuntimeException("Image does not split to 3 channels!");
}
// Adaptive Thresholding
Imgproc.adaptiveThreshold(vMat, vMat, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 9, 10); // 5,
// 25
// Erosion & Dilation
vMat = CVUtils.invertMat(vMat);
Mat kernal = new Mat();
org.opencv.core.Point p = new org.opencv.core.Point(-1, -1);
LinkedList<MatOfPoint> contours = new LinkedList<MatOfPoint>();
LinkedList<MatOfPoint> finalListOfContours = new LinkedList<MatOfPoint>();
for (int i = 0; finalListOfContours.size() == 0; i++) {
Mat dst = vMat.clone();
contours.clear();
Imgproc.dilate(vMat, dst, kernal, p, 1);
Imgproc.erode(dst, vMat, kernal, p, 1);
Imgproc.dilate(vMat, dst, kernal, p, 3 * (i + 1));
Imgproc.erode(dst, vMat, kernal, p, 3 * (i + 1));
Utils.out.println("i:" + i);
// Get contours
Mat hierarchy = new Mat();
Imgproc.findContours(vMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);
// Filter out bad contours
finalListOfContours.clear();
for (int j = 0; j < contours.size(); j++)
{
if (Imgproc.contourArea(contours.get(j)) > (vMat.rows() * vMat.cols() * 0.005))
{// 0.01 is default
finalListOfContours.add(contours.get(j));
}
}
}
contours = null;
LinkedList<DMImage> dmImageList = new LinkedList<DMImage>();
DMImageFactory factory = new DMImageFactory();
JSUtils.resetImageNameCounter();
// Copy across image parts
for (int i = 0; i < finalListOfContours.size(); i++)
{
MatOfPoint thisContour = finalListOfContours.get(i);
Rect bb = Imgproc.boundingRect(thisContour);
// Translate contours
Point topLeft = new Point(bb.x, bb.y);
Mat matChunk = Mat.zeros(bb.size(), image.getType());
MatOfPoint translatedContour = CVUtils.translateMatOfPoints(thisContour, topLeft);
matChunk = mat.submat(bb).clone();
// Draw fill mask
Mat contourMask = new Mat(matChunk.size(), CvType.CV_32SC1);
contourMask.setTo(new org.opencv.core.Scalar(0));
LinkedList<MatOfPoint> listOfPoints = new LinkedList<MatOfPoint>();
listOfPoints.add(translatedContour);
Core.fillPoly(contourMask, listOfPoints, new org.opencv.core.Scalar(-1));
// Add to DMImage list
Imgproc.cvtColor(matChunk, matChunk, Imgproc.COLOR_HSV2BGR);
BufferedImage bufImage = CVUtils.getAlphaBufferedImageFromMat(matChunk, contourMask);
// Add positional info
String name = JSUtils.generateImageName();
DMImage dmImage = factory.new DMImage(name, topLeft, bufImage);
dmImageList.add(dmImage);
}
if (finalListOfContours.size() == 0) {
JOptionPane.showMessageDialog(PaperPanel.getInstance(), "We could not find any characters in this image, please try again!");
PaperPanel.getInstance().webcamCancel();
}
return dmImageList;
}
public class DMImage extends DMObject
{
private static final long serialVersionUID = 1L;
private BufferedImage mSourceImage = null;
private BufferedImage mScaledImage = null;
private Dimension mPreferredDimension = null;
private URL mFileURL = null;
private Evaluator mEvaluatorNodeLocation = null;
private Evaluator mEvaluatorNodeSize = null;
public void setFileURL(URL mFileURL)
{
this.mFileURL = mFileURL;
}
protected DMImage(String name, Point origin, BufferedImage image) {
super(name);
mHandleBorder = new HandleBorder(false);
mPreferredDimension = new Dimension(image.getWidth() + (2 * mHandleBorder.getThickness()), image.getHeight() + (2 * mHandleBorder.getThickness()));
setMinimumSize(mPreferredDimension);
mSourceImage = image;
setBorder(mHandleBorder);
setPreferredLocation(origin, ManipulationSource.SOURCE_EXECUTION);
addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter);
}
@Override
protected void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
if (mScaledImage == null)
g2.drawImage(mSourceImage, null, mHandleBorder.getThickness(), mHandleBorder.getThickness());
else
g2.drawImage(mScaledImage, null, mHandleBorder.getThickness(), mHandleBorder.getThickness());
}
@Override
public Dimension getMaximumSize()
{
return mPreferredDimension;
}
@Override
public void setSize(int width, int height)
{
stretch(width, height);
super.setSize(width, height);
}
@Override
public void setSize(Dimension d)
{
stretch(d.width, d.height);
super.setSize(d);
}
public void stretch(int width, int height)
{
// Incoming x and y are relative to the DMObject
int newHeight = height - (2 * mHandleBorder.getThickness());
int newWidth = width - (2 * mHandleBorder.getThickness());
if (newWidth > 0 && newHeight > 0) {
BufferedImage stretchedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
double sx = Math.max(0.0001, (double) newWidth / (double) mSourceImage.getWidth());
double sy = Math.max(0.0001, (double) newHeight / (double) mSourceImage.getHeight());
AffineTransform at = new AffineTransform();
at.scale(sx, sy);
AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
scaleOp.filter(mSourceImage, stretchedImage);
mScaledImage = stretchedImage;
}
}
@Override
public String toString()
{
return "[DMImage]";
}
public BufferedImage getImage()
{
if (mScaledImage == null)
return mSourceImage;
else
return mScaledImage;
}
public URL getURL()
{
return mFileURL;
}
public Evaluator getEvaluatorNode(ASTModification.ASTModificationType mod)
{
switch (mod)
{
case MOD_LOCATION:
return mEvaluatorNodeLocation;
case MOD_SIZE:
return mEvaluatorNodeSize;
}
return null;
}
public void setEvaluatorNode(Evaluator e, ASTModification.ASTModificationType mod)
{
switch (mod)
{
case MOD_LOCATION:
mEvaluatorNodeLocation = e;
break;
case MOD_SIZE:
mEvaluatorNodeSize = e;
break;
}
}
}
}