Apply FFT on BufferedImage give me an ArrayIndexOutOfBoundsException - java

I create a BufferedImage with Robot and try to apply FFT algorithm from rosetta code on the DataBufferInt generated by the Robot but it's fail in the fft method and I don't know why.
Robot r = new Robot();
Rectangle rect = new Rectangle(10,10,200,200);
BufferedImage capture = r.createScreenCapture(rect);
// All data in getDataBuffer() seems to be negative
int[] pixels = ((DataBufferInt)buffer.getRaster().getDataBuffer()).getData();
Complex[] cinput = new Complex[pixels.length];
for (int i = 0; i < pixels.length; i++) {
cinput[i] = new Complex(pixels[i], 0.0);
}
// Fail (method from rosetta code)
FastFourierTransform.fft(cinput);
Give me:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 40000
at engine.FastFourierTransform.fft(FastFourierTransform.java:42)
at engine.ImageProcessing.FFT(ImageProcessing.java:30)
at test.Testor.main(Testor.java:24)
I'm doing something wrong ?

You can use the Catalano Framework, you can easily perform the fast fourier transform. Also works for MxN-sized images.
Robot r = new Robot();
Rectangle rect = new Rectangle(10,10,200,200);
BufferedImage capture = r.createScreenCapture(rect);
FastBitmap fb = new FastBitmap(capture);
fb.toGrayscale();
FourierTransform ft = new FourierTransform(fb);
ft.Forward();
fb = ft.toFastBitmap();
//Display the image
JOptionPane.showMessageDialog(null, fb.toIcon());

Related

Remove PdfName.Rotate value without rotation

I have to combine multiple pages from several files into new one PDF. The page orientation of all the pages must be portrait.
After this work is done, I am using a couple of programs to reset the rotation to zero without really rotate the page.
I want to use itext to remove the rotation value.
Taked from itext examples, I've tried something like this:
protected void manipulatePdf(String dest) throws Exception {
PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(DEST));
int n = pdfDoc.getNumberOfPages();
PdfPage page;
PdfNumber rotate;
for (int p = 1; p <= n; p++) {
page = pdfDoc.getPage(p);
rotate = page.getPdfObject().getAsNumber(PdfName.Rotate);
page.setRotation(0);
pdfDoc.close();
}
}
This:
PdfDictionary diccionario = page.getPdfObject();
diccionario.Remove(iText.Kernel.Pdf.PdfName.Rotate);
And the function CopyPagesTo with the same result: The pages orientation has been altered.
Here there is an example file with 0, 90, 180 y 270 degrees.
The goal is set rotate value of all pages to zero keeping portrait mode:
https://filebin.ca/4vep0uuU1p2s/1.pdf
Any advice would be greatly appreciated.
I have found a solution using the SetIgnorePageRotationForContent function.
VB.NET example:
Dim srcPdf As iText.Kernel.Pdf.PdfDocument = New iText.Kernel.Pdf.PdfDocument(New iText.Kernel.Pdf.PdfReader(srcFile))
Dim destPDF As New iText.Kernel.Pdf.PdfDocument(New iText.Kernel.Pdf.PdfWriter(destFile))
For contador = 1 To srcPdf.GetNumberOfPages
Dim srcPage = srcPdf.GetPage(contador)
Dim rotacion As iText.Kernel.Pdf.PdfNumber = srcPage.GetPdfObject().GetAsNumber(iText.Kernel.Pdf.PdfName.Rotate)
If IsNothing(rotacion) OrElse rotacion.IntValue = 0 Then
srcPdf.CopyPagesTo(contador, contador, destPDF)
Continue For
End If
Dim destPage As iText.Kernel.Pdf.PdfPage = destPDF.AddNewPage(New iText.Kernel.Geom.PageSize(srcPage.GetPageSizeWithRotation))
If rotacion.IntValue = 180 Then
destPage.GetPdfObject().Put(iText.Kernel.Pdf.PdfName.Rotate, New iText.Kernel.Pdf.PdfNumber(180))
Else
destPage.GetPdfObject().Put(iText.Kernel.Pdf.PdfName.Rotate, New iText.Kernel.Pdf.PdfNumber(rotacion.IntValue + 180))
End If
destPage.SetIgnorePageRotationForContent(True)
Dim canvas As New iText.Kernel.Pdf.Canvas.PdfCanvas(destPage)
Dim pageCopy As iText.Kernel.Pdf.Xobject.PdfFormXObject = srcPage.CopyAsFormXObject(destPDF)
canvas.AddXObject(pageCopy, 0, 0)
destPage.GetPdfObject().Remove(iText.Kernel.Pdf.PdfName.Rotate)
Next
destPDF.Close()
srcPdf.Close()

OpenCV - Java - How to remove some pixels around a cluster

I am doing a project where I need to identify certain areas of the image. After processing the image and removing all the unnecessary things I finally get the area which I need as shown in the image (area inside the green circle).
I am unable to draw a circle around that area using OpenCV. I am currently using the Java version of OpenCV. If someone can point me to the right direction on how to implement that green circle over the image, it will be very helpful.
Things I have tried to detect that area.
blob detector - Did not achieve much.
Cluster - Same as blob detector.
HoughCircles - Draws unnecessary circles in the image.
FindContour - Did not draw anything since it is not a perfect circle, ellipse or any other well known polygon.
I appreciate your help.
Here is a solution:
Opening in order to clean the image from all the thin/elongate patterns.
Connected component labeling in order to count the remaining patterns
Size counting of each remaining pattern
The biggest pattern is the one you want to circle.
Note: is you want to perfectly preserve the pattern, you can replace the opening by an opening by reconstruction (erosion + geodesic reconstruction).
I finally found a solution for my problem. I used the feature detector from the OpenCV library and gave the right threshold to the detector. This did the trick for me. The code in Java looks like below.
public static void main(String[] args){
try{
//Validation whether a file name is passed to the function
if(args.length == 0){
System.out.println("here...");
log.error("No file was passed to the function");
throw new IOException();
}
//Read the image from the input
Mat inputMat = Highgui.imread(args[0],Highgui.CV_LOAD_IMAGE_GRAYSCALE);
//Create a feature detector. In this case we are using SURF (Speeded-Up Robust Features) detector.
MatOfKeyPoint objectKeyPoints = new MatOfKeyPoint();
FeatureDetector featureDetector = FeatureDetector.create(FeatureDetector.SURF);
//A temporary file is created to input Hessian Threshold to the SURF detector
File tempFile = File.createTempFile("config", ".yml");
String settings = "%YAML:1.0\nhessianThreshold: 7000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n";
FileWriter writer = new FileWriter(tempFile, false);
writer.write(settings);
writer.close();
//Read the configuration from the temporary file to assign the threshold for the detector
featureDetector.read(tempFile.getPath());
//Detect the features in the image provided
featureDetector.detect(inputMat, objectKeyPoints);
//Iterate through the list of key points detected in the previous step and find the Key Point with the largest size
List<KeyPoint> objectKeyPointList = objectKeyPoints.toList();
KeyPoint impKeyPoint = new KeyPoint();
for(int i=0; i<objectKeyPointList.size(); i++){
if(impKeyPoint == null){
impKeyPoint = objectKeyPointList.get(i);
}
else if(impKeyPoint.size < objectKeyPointList.get(i).size){
impKeyPoint = objectKeyPointList.get(i);
}
}
//If the size of the Key Point is greater than 120 then reduce the size to 120 and if the size is less than 120 then increase to 120
if(impKeyPoint.size > 120){
KeyPoint tempKeyPoint = new KeyPoint();
tempKeyPoint = impKeyPoint;
tempKeyPoint.size = 120;
impKeyPoint = tempKeyPoint;
}
else if(impKeyPoint.size < 120){
KeyPoint tempKeyPoint = new KeyPoint();
tempKeyPoint = impKeyPoint;
tempKeyPoint.size = 120;
impKeyPoint = tempKeyPoint;
}
//Convert the Key Point to MatOfKeyPoint since drawKeyPoints accepts only MatOfKeyPoint
MatOfKeyPoint impMatOfKeyPoint = new MatOfKeyPoint(impKeyPoint);
//Mat for drawing the circle in the image
Mat outputImage = new Mat(inputMat.rows(), inputMat.cols(), Highgui.CV_LOAD_IMAGE_COLOR);
//Green color for the circle
Scalar greenCircle = new Scalar(0, 255, 0);
//Draw the circle around the optic nerve when detected
Features2d.drawKeypoints(inputMat, impMatOfKeyPoint, outputImage, greenCircle, Features2d.DRAW_RICH_KEYPOINTS);
//Write the image to a file
Highgui.imwrite("surf_keypoints.png", outputImage);
}catch(Exception e){
log.fatal(e.getMessage());
}
}
Hope this is helpful for others.

How can I draw rectangle with MatOfKeyPoint for Text Detection | Java

I am working on a real time text detection and recognition with OpenCV4Android. Recognition part is totally completed. However, I have to ask question about text detection. I' m using the MSER FeatureDetector for detection text.
This is the real time and calling the method part:
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
carrierMat = inputFrame.gray();
carrierMat = General.MSER(carrierMat);
return carrierMat;
}
And this is the basic MSER implementation:
private static FeatureDetector fd = FeatureDetector.create(FeatureDetector.MSER);
private static MatOfKeyPoint mokp = new MatOfKeyPoint();
private static Mat edges = new Mat();
public static Mat MSER(Mat mat) {
//for mask
Imgproc.Canny(mat, edges, 400, 450);
fd.detect(mat, mokp, edges);
//for drawing keypoints
Features2d.drawKeypoints(mat, mokp, mat);
return mat;
}
It works fine for finding text with edges mask.
I would like to draw a rectangles for clusters like this:
or this:
You can assume that I have the right points.
As you can see, fd.detect() method is returning a MatOfKeyPoint. Hence I' ve tried this method for drawing rectangle:
public static Mat MSER_(Mat mat) {
fd.detect(mat, mokp);
KeyPoint[] refKp = mokp.toArray();
Point[] refPts = new Point[refKp.length];
for (int i = 0; i < refKp.length; i++) {
refPts[i] = refKp[i].pt;
}
MatOfPoint2f refMatPt = new MatOfPoint2f(refPts);
MatOfPoint2f approxCurve = new MatOfPoint2f();
//Processing on mMOP2f1 which is in type MatOfPoint2f
double approxDistance = Imgproc.arcLength(refMatPt, true) * 0.02;
Imgproc.approxPolyDP(refMatPt, approxCurve, approxDistance, true);
//Convert back to MatOfPoint
MatOfPoint points = new MatOfPoint(approxCurve.toArray());
// Get bounding rect
Rect rect = Imgproc.boundingRect(points);
// draw enclosing rectangle (all same color, but you could use variable i to make them unique)
Imgproc.rectangle(mat, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), Detect_Color_, 5);
//Features2d.drawKeypoints(mat, mokp, mat);
return mat;
}
But when I was trying to Imgproc.arcLength() method, it suddenly stopped. I gave a random approxDistance value for Imgproc.approxPolyDP() method like 0.1, it doesn' t work really efficiently.
So how can I draw rectangle for detected text?
I tested your code and had exactly the same problem.
For now I still can't find the problem within.
But I found a project using both "MSER" and "Morphological".
you can find it here .
The project have very simple structure and the author put the
text detection in "onCameraFrame" method just like you.
I implemented the method from that project and it worked,
but the result was still not very good.
If you seek better text detection tool, here's two of them.
Stroke Width Transform(SWT):
A whole new method for finding text area. It's fast and efficient. however it is only available in c++ or python. you can find some example here.
Class-specific Extremal Regions using class ERFilter:An advanced version of the MSER. Unfortunately, it is only available in OpenCV 3.0.0-dev. You can't use it in current version of OpenCV4Android. The document is here.
To be honest I am new in this area(2 months), but I hope these information can help you finish your project.
(update:2015/9/13)
I've translated a c++ method from a post.
It works far better than the first github project I mentioned.
Here is the code:
public void apply(Mat src, Mat dst) {
if (dst != src) {
src.copyTo(dst);
}
Mat img_gray,img_sobel, img_threshold, element;
img_gray=new Mat();
Imgproc.cvtColor(src, img_gray, Imgproc.COLOR_RGB2GRAY);
img_sobel=new Mat();
Imgproc.Sobel(img_gray, img_sobel, CvType.CV_8U, 1, 0, 3, 1, 0,Core.BORDER_DEFAULT);
img_threshold=new Mat();
Imgproc.threshold(img_sobel, img_threshold, 0, 255, Imgproc.THRESH_OTSU+Imgproc.THRESH_BINARY);
element=new Mat();
element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(17, 3) );
Imgproc.morphologyEx(img_threshold, img_threshold, Imgproc.MORPH_CLOSE, element);
//Does the trick
List<MatOfPoint> contours=new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat();
Imgproc.findContours(img_threshold, contours, hierarchy, 0, 1);
List<MatOfPoint> contours_poly=new ArrayList<MatOfPoint>(contours.size());
contours_poly.addAll(contours);
MatOfPoint2f mMOP2f1,mMOP2f2;
mMOP2f1=new MatOfPoint2f();
mMOP2f2=new MatOfPoint2f();
for( int i = 0; i < contours.size(); i++ )
if (contours.get(i).toList().size()>100)
{
contours.get(i).convertTo(mMOP2f1, CvType.CV_32FC2);
Imgproc.approxPolyDP(mMOP2f1,mMOP2f2, 3, true );
mMOP2f2.convertTo(contours_poly.get(i), CvType.CV_32S);
Rect appRect=Imgproc.boundingRect(contours_poly.get(i));
if (appRect.width>appRect.height)
{
Imgproc.rectangle(dst, new Point(appRect.x,appRect.y) ,new Point(appRect.x+appRect.width,appRect.y+appRect.height), new Scalar(255,0,0));
}
}
}

Getting Mats from frames in a gif using OpenCV and Java

I am trying to get frames from a gif using OpenCV. I found Convert each animated GIF frame to a separate BufferedImage and used the second suggestion. I modified it slightly to return an array of Mats instead of BufferedImages.
I tried two methods to get bufferedImages from the gif. Each presented different problems.
With the previous thread's suggestion
BufferedImage fImage=ir.read(i);
The program calls a "ArrayIndexOutOfBoundsException: 4096"
With the original code from the previous thread.
BufferedImage fImage=ir.getRawImageType(i).createBufferedImage(ir.getWidth(i),ir.getHeight(i));
Each frame is a monotone color(not all black though) and the mat derived from the BufferedImage is empty.
System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
ArrayList<Mat> frames = new ArrayList<Mat>();
ImageReader ir = new GIFImageReader(new GIFImageReaderSpi());
ir.setInput(ImageIO.createImageInputStream(new File("ronPaulTestImage.gif")));
for(int i = 0; i < ir.getNumImages(true); i++){
BufferedImage fImage=ir.read(i);
//BufferedImage fImage=ir.getRawImageType(i).createBufferedImage(ir.getWidth(i), ir.getHeight(i));
fImage = toBufferedImageOfType(fImage, BufferedImage.TYPE_3BYTE_BGR);
//byte[] pixels = ((DataBufferByte) r.getRaster().getDataBuffer()).getData();
Mat m=new Mat();
//m.put(0,0,pixels);
m.put(0, 0,((DataBufferByte) fImage.getRaster().getDataBuffer()).getData());
if(i==40){
//a test, writes the mat and the image at the specified frame to files, exits
ImageIO.write(fImage,"jpg",new File("TestError.jpg"));
Imgcodecs.imwrite("TestErrorMat.jpg",m);
System.exit(0);
}
Here is the gif I used
Following Spektre's advice I found a better gif which fixed the monochromatic bufferedImages. The lack of viewable Mats was caused by my usage of the default constructor when declaring the Mat.
Working Code
public static ArrayList<Mat> getFrames(File gif) throws IOException{
ArrayList<Mat> frames = new ArrayList<Mat>();
ImageReader ir = new GIFImageReader(new GIFImageReaderSpi());
ir.setInput(ImageIO.createImageInputStream(gif));
for(int i = 0; i < ir.getNumImages(true); i++){
BufferedImage fImage=ir.read(i);
fImage = toBufferedImageOfType(fImage, BufferedImage.TYPE_3BYTE_BGR);
byte[] pixels = ((DataBufferByte) fImage.getRaster().getDataBuffer()).getData();
Mat m=new Mat(fImage.getHeight(), fImage.getWidth(), CvType.CV_8UC3);
m.put(0,0,pixels);
if(i==15){//a test, writes the mat and the image at the specified frame to files, exits
ImageIO.write(fImage,"jpg",new File("TestError.jpg"));
Imgcodecs.imwrite("TestErrorMat.jpg",m);
System.exit(0);
}
frames.add(m);
}
return frames;
}
I am not using libs for gif nor Java nor OpenCV but the ArrayIndexOutOfBoundsException: 4096
means that the dictionary is not cleared properly. The gif of yours is buggy I tested it and it contains errors not enough clear codes are present for some frames. If your GIF decoder does not check/handle such case then it simply crash because its dictionary growth more then GIF limit 4096/12bit
Try another GIF not some buggy ones ...
have tested your gif and it has around 7 clear codes per frame and contains 941 errors in total (absence of clear code resulting in dictionary overrun)
If you have source code for the GIF decoder
then just find part of decoder where new item is added to dictionary and add
if (dictionary_items<4096)
before it ... If you ignore the wrong entries the image looks still OK most likely the encoder in which this was created was not properly coded.
with bytedeco opencv, simple way to get the first frame of gif:
import java.awt.image.{BufferedImage, DataBufferByte}
import java.io.ByteArrayInputStream
import com.sun.imageio.plugins.gif.{GIFImageReader, GIFImageReaderSpi}
import javax.imageio.ImageIO
import javax.swing.JFrame
import org.bytedeco.javacv.{CanvasFrame, OpenCVFrameConverter}
import org.bytedeco.opencv.opencv_core.Mat
import org.opencv.core.CvType
def toMat(bi: BufferedImage): Mat = {
val convertedImage = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_3BYTE_BGR)
val graphics = convertedImage.getGraphics
graphics.drawImage(bi, 0, 0, null)
graphics.dispose()
val data = convertedImage.getRaster.getDataBuffer.asInstanceOf[DataBufferByte].getData
val mat = new Mat(convertedImage.getHeight, convertedImage.getWidth, CvType.CV_8UC3)
mat.data.put(data: _*)
mat
}
def show(image: Mat, title: String): Unit = {
val canvas = new CanvasFrame(title, 1)
canvas.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE)
canvas.showImage(new OpenCVFrameConverter.ToMat().convert(image))
}
val imageByteArrayOfGif = Array(....) // can be downloaded with java.net.HttpURLConnection
val ir = new GIFImageReader(new GIFImageReaderSpi())
val in = new ByteArrayInputStream(imageByteArray)
ir.setInput(ImageIO.createImageInputStream(in))
val bi = ir.read(0) // first frame of gif
val mat = toMat(bi)
show(mat, "buffered2mat")

What's wrong with my java code to rotate a jpeg photo?

I simply want to enable the user of my web site to change the orientation of a submitted photo from horizontal to vertical. Here's my code:
public static final void rotatePhoto(String jpgFilename){
BufferedImage originalImage = null, newImage=null;
try{
File file = new File(jpgFilename);
originalImage = ImageIO.read(file);
System.out.println("Photo.rotatePhoto(" +jpgFilename +") originalImage.getWidth(null)=" +originalImage.getWidth(null) +" originalImage.getHeight(null)=" +originalImage.getHeight(null) );
java.awt.image.AffineTransformOp opRotated = new java.awt.image.AffineTransformOp( java.awt.geom.AffineTransform.getQuadrantRotateInstance(1), null );
newImage = opRotated.createCompatibleDestImage(originalImage, originalImage.getColorModel());
opRotated.filter(originalImage, newImage);
}catch (IOException e){
}
/// Write result to file::::::::::::::::::::::::::::::::::::::::::::::::::::
try{
File outputfile = new File(testFilename);
ImageIO.write(newImage, "jpg", outputfile);
}catch(IOException ioE){
}
}
Problem is I get this error even though the System.out.println shows the width and height to be 640x480
java.awt.image.RasterFormatException: Transformed width (0) is less than or equal to 0.
java.awt.image.AffineTransformOp.createCompatibleDestImage(AffineTransformOp.java:447)
base.Photo.rotatePhoto(Photo.java:135)
base.ProcessContent.handleInput(ProcessContent.java:245)
servlets.ProcessServlet.doPost(ProcessServlet.java:74)
servlets.ProcessServlet.doGet(ProcessServlet.java:33)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
Any ideas or workarounds?
Try creating a new AffineTransform from scratch and using it in your AffineTransformOp constructor:
AffineTransform tx = new AffineTransform();
tx.rotate(Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
newImage = op.filter(originalImage, newImage);
You also have to make sure newImage contains the data returned by the filter() method.
Oddly enough, this will only work when you set the formatName in ImageIO.write() to "png". I tried using jpg and the result was a black picture.
By using: AffineTransform.getQuadrantRotateInstance(1);
Your AffineTransform is rotating by a positive number of quadrants by axis. That will mess up the Transform Operation since it depends on the x and y, whenever it creates the compatible image.
int w = r.x + r.width;
int h = r.y + r.height;
if (w <= 0) {
throw new RasterFormatException("Transformed width ("+w+
") is less than or equal to 0.");
}
I would recommend doing it yourself:
public final void rotatePhoto(String jpgFilename) throws IOException {
File file = new File(jpgFilename);
BufferedImage originalImage = ImageIO.read(file);
// You could use Math.PI / 2, depends on your input.
AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate(Math.toRadians(90), originalImage.getWidth() / 2, originalImage.getHeight() / 2);
// Now lets make that transform an operation, and we use it.
AffineTransformOp opRotated = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage newImage = opRotated.filter(originalImage, null);
// Save the image.
File outputfile = new File("rotated.jpg");
ImageIO.write(newImage, "jpg", outputfile);
}
UPDATE: Btw, it has been answered before on How do I write a servlet which rotates images?

Categories