Dear members,
Does anyone has an example on how to determine deskew and also rotate the image to fix it with imageJ? I am new to the platform. Thanks in advance, Carlos. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Carlos,
I'm not sure what you mean by Deskew. To rotate manually: Use the angle tool on the toolbar to measure an angle, then Image > Transform > Rotate and enter the angle. You might also look at Plugins > Transform > and Interactive Affine, Interactive Perspective, or Landmark correspondence. Those might help if you had a reference image already in the target orientation. Charles -----Original Message----- From: ImageJ Interest Group [mailto:[hidden email]] On Behalf Of C.F.Scheidecker Antunes Sent: Friday, March 08, 2013 11:30 AM To: [hidden email] Subject: How to perform Deskew detection and also skew fix with imageJ Dear members, Does anyone has an example on how to determine deskew and also rotate the image to fix it with imageJ? I am new to the platform. Thanks in advance, Carlos. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
I not sure too but I i'll put a simple deskew code:
public static BufferedImage imageDeskew(BufferedImage image) { double tempoInicial = System.currentTimeMillis(); BufferedImage imageOut; ImageDeskew sk = new ImageDeskew(image); // Descobre o angulo double angle = sk.getSkewAngle(); System.out.println("Angulo deskew: " + angle); // Rotaciona a imagem if ((angle > MINIMUM_DESKEW_THRESHOLD || angle < -(MINIMUM_DESKEW_THRESHOLD))) { imageOut = ImageTools.rotate(image, -angle, image.getWidth() / 2, image.getHeight() / 2); } else { imageOut = image; } double tempoFinal = System.currentTimeMillis(); System.out.println("# Tempo para deskew: " + ((tempoFinal-tempoInicial)/1000) + " segundos."); return imageOut; } ---- package br.com.infosolo.scanner.util; import java.awt.image.BufferedImage; public class ImageDeskew { // Representation of a line in the image. class HougLine { //' Count of points in the line. public int count; // Index in Matrix. public int index; // The line is represented as all x,y that solve y*cos(alpha)-x*sin(alpha)=d public double alpha; public double d; } // The Bitmap //Dim cBmp As Bitmap BufferedImage cBmp; // The range of angles to search for lines double cAlphaStart = -20; double cAlphaStep = 0.2; int cSteps = 40 * 5; // Precalculation of sin and cos. double cSinA[]; double cCosA[]; // Range of d double cDMin; double cDStep = 1; int cDCount; // Count of points that fit in a line. int cHMatrix[]; // Calculate the skew angle of the image cBmp. public double getSkewAngle() { HougLine hl[]; double sum = 0; int count = 0; // Hough Transformation calc(); // Top 20 of the detected lines in the image. hl = getTop(20); // Average angle of the lines for (int i = 0; i < 20; i++) { sum += hl[i].alpha; count++; } return sum / count; } // Calculate the Count lines in the image with most points. private HougLine[] getTop(int count) { HougLine hl[]; int j; HougLine tmp; int alphaIndex; int dIndex; hl = new HougLine[count]; for (int i = 0; i < count; i++) { hl[i] = new HougLine(); } for (int i = 0; i < cHMatrix.length; i++) { if (cHMatrix[i] > hl[count - 1].count) { hl[count - 1].count = cHMatrix[i]; hl[count - 1].index = i; j = count - 1; while (j > 0 && hl[j].count > hl[j - 1].count) { tmp = hl[j]; hl[j] = hl[j - 1]; hl[j - 1] = tmp; j--; } } } for (int i = 0; i < count; i++) { //dIndex = (int)(hl[i].index / cSteps); Double d = new Double(hl[i].index / cSteps); dIndex = d.intValue(); alphaIndex = hl[i].index - dIndex * cSteps; hl[i].alpha = getAlpha(alphaIndex); hl[i].d = dIndex + cDMin; } return hl; } public ImageDeskew(BufferedImage bmp) { cBmp = bmp; } // Hough Transforamtion: private void calc() { int hMin = cBmp.getHeight() / 4; int hMax = cBmp.getHeight() * 3 / 4; init(); for (int y = hMin; y <= hMax; y++) { for (int x = 1; x <= cBmp.getWidth() - 2; x++) { // Only lower edges are considered. if (ImageTools.isBlack(cBmp, x, y)) { if (!ImageTools.isBlack(cBmp, x, y + 1)) { calc(x, y); } } } } } // Calculate all lines through the point (x,y). private void calc(int x, int y) { double d; int dIndex; int index; for (int alpha = 0; alpha < cSteps; alpha++) { d = y * cCosA[alpha] - x * cSinA[alpha]; dIndex = (int) (d - cDMin); index = dIndex * cSteps + alpha; //Try cHMatrix[index] = cHMatrix[index] + 1; //Catch ex As Exception // Debug.WriteLine(ex.ToString) //End Try } } private void init() { double angle; // Precalculation of sin and cos. //ReDim cSinA(cSteps - 1) //ReDim cCosA(cSteps - 1) cSinA = new double[cSteps]; cCosA = new double[cSteps]; for (int i = 0; i < cSteps; i++) { angle = getAlpha(i) * Math.PI / 180.0D; cSinA[i] = Math.sin(angle); cCosA[i] = Math.cos(angle); } // Range of d: cDMin = -cBmp.getWidth(); cDCount = (int) (2 * (cBmp.getWidth() + cBmp.getHeight()) / cDStep); cHMatrix = new int[cDCount * cSteps]; } public double getAlpha(int index) { return cAlphaStart + index * cAlphaStep; } } ------ /** * Rotate a image by angle informed. * @param image * @param angle * @param cx Center of width * @param cy Center of height * @return */ public static BufferedImage rotate(BufferedImage image, double angle, int cx, int cy) { int width = image.getWidth(null); int height = image.getHeight(null); int minX, minY, maxX, maxY; minX = minY = maxX = maxY = 0; int[] corners = { 0, 0, width, 0, width, height, 0, height }; double theta = Math.toRadians(angle); for (int i = 0; i < corners.length; i += 2) { int x = (int) (Math.cos(theta) * (corners[i] - cx) - Math.sin(theta) * (corners[i + 1] - cy) + cx); int y = (int) (Math.sin(theta) * (corners[i] - cx) + Math.cos(theta) * (corners[i + 1] - cy) + cy); if (x > maxX) { maxX = x; } if (x < minX) { minX = x; } if (y > maxY) { maxY = y; } if (y < minY) { minY = y; } } cx = (cx - minX); cy = (cy - minY); int type = image.getType(); if (type == 0) { type = BufferedImage.TYPE_INT_RGB; if (hasAlpha(image)) { type = BufferedImage.TYPE_INT_ARGB; } } BufferedImage bi = new BufferedImage((maxX - minX), (maxY - minY), type); Graphics2D g2 = bi.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g2.setBackground(Color.white); g2.fillRect(0, 0, bi.getWidth(), bi.getHeight()); AffineTransform at = new AffineTransform(); at.rotate(theta, cx, cy); g2.setTransform(at); g2.drawImage(image, -minX, -minY, null); g2.dispose(); return bi; } --- Best regards. David On 03/08/2013 03:55 PM, Anderson, Charles (DNR) wrote: > Carlos, > > I'm not sure what you mean by Deskew. > > To rotate manually: > Use the angle tool on the toolbar to measure an angle, then Image > Transform > Rotate and enter the angle. > > You might also look at Plugins > Transform > and Interactive Affine, Interactive Perspective, or Landmark correspondence. Those might help if you had a reference image already in the target orientation. > > Charles > > -----Original Message----- > From: ImageJ Interest Group [mailto:[hidden email]] On Behalf Of C.F.Scheidecker Antunes > Sent: Friday, March 08, 2013 11:30 AM > To: [hidden email] > Subject: How to perform Deskew detection and also skew fix with imageJ > > Dear members, > > Does anyone has an example on how to determine deskew and also rotate the image to fix it with imageJ? > > I am new to the platform. > > Thanks in advance, > > Carlos. > > -- > ImageJ mailing list: http://imagej.nih.gov/ij/list.html > > -- > ImageJ mailing list: http://imagej.nih.gov/ij/list.html -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
David,
This is great, Thanks! (Obrigado). I wonder if you need to have the image in binary color first for this to be effective. Meaning, 0 and 255 not with many different colors. Thanks, Carlos. On Fri, Mar 8, 2013 at 12:03 PM, David Reis <[hidden email]>wrote: > I not sure too but I i'll put a simple deskew code: > > public static BufferedImage imageDeskew(BufferedImage image) { > double tempoInicial = System.currentTimeMillis(); > BufferedImage imageOut; > ImageDeskew sk = new ImageDeskew(image); > > // Descobre o angulo > double angle = sk.getSkewAngle(); > System.out.println("Angulo deskew: " + angle); > > // Rotaciona a imagem > if ((angle > MINIMUM_DESKEW_THRESHOLD || angle < > -(MINIMUM_DESKEW_THRESHOLD))) { > imageOut = ImageTools.rotate(image, -angle, image.getWidth() / > 2, image.getHeight() / 2); > } else { > imageOut = image; > } > double tempoFinal = System.currentTimeMillis(); > System.out.println("# Tempo para deskew: " + > ((tempoFinal-tempoInicial)/**1000) + " segundos."); > return imageOut; > } > > > ---- > > package br.com.infosolo.scanner.util; > > import java.awt.image.BufferedImage; > > public class ImageDeskew { > > // Representation of a line in the image. > class HougLine { > //' Count of points in the line. > public int count; > > // Index in Matrix. > public int index; > > // The line is represented as all x,y that solve > y*cos(alpha)-x*sin(alpha)=d > public double alpha; > public double d; > } > > // The Bitmap > //Dim cBmp As Bitmap > BufferedImage cBmp; > > // The range of angles to search for lines > double cAlphaStart = -20; > double cAlphaStep = 0.2; > int cSteps = 40 * 5; > > // Precalculation of sin and cos. > double cSinA[]; > double cCosA[]; > > // Range of d > double cDMin; > double cDStep = 1; > int cDCount; > > // Count of points that fit in a line. > int cHMatrix[]; > > // Calculate the skew angle of the image cBmp. > public double getSkewAngle() { > HougLine hl[]; > double sum = 0; > int count = 0; > > // Hough Transformation > calc(); > > // Top 20 of the detected lines in the image. > hl = getTop(20); > > // Average angle of the lines > for (int i = 0; i < 20; i++) { > sum += hl[i].alpha; > count++; > } > return sum / count; > } > > // Calculate the Count lines in the image with most points. > private HougLine[] getTop(int count) { > HougLine hl[]; > int j; > HougLine tmp; > int alphaIndex; > int dIndex; > > hl = new HougLine[count]; > > for (int i = 0; i < count; i++) { > hl[i] = new HougLine(); > } > > for (int i = 0; i < cHMatrix.length; i++) { > if (cHMatrix[i] > hl[count - 1].count) { > hl[count - 1].count = cHMatrix[i]; > hl[count - 1].index = i; > j = count - 1; > while (j > 0 && hl[j].count > hl[j - 1].count) { > tmp = hl[j]; > hl[j] = hl[j - 1]; > hl[j - 1] = tmp; > j--; > } > } > } > > for (int i = 0; i < count; i++) { > //dIndex = (int)(hl[i].index / cSteps); > Double d = new Double(hl[i].index / cSteps); > dIndex = d.intValue(); > > alphaIndex = hl[i].index - dIndex * cSteps; > hl[i].alpha = getAlpha(alphaIndex); > hl[i].d = dIndex + cDMin; > } > return hl; > } > > public ImageDeskew(BufferedImage bmp) { > cBmp = bmp; > } > > // Hough Transforamtion: > private void calc() { > int hMin = cBmp.getHeight() / 4; > int hMax = cBmp.getHeight() * 3 / 4; > > init(); > > for (int y = hMin; y <= hMax; y++) { > for (int x = 1; x <= cBmp.getWidth() - 2; x++) { > // Only lower edges are considered. > if (ImageTools.isBlack(cBmp, x, y)) { > if (!ImageTools.isBlack(cBmp, x, y + 1)) { > calc(x, y); > } > } > } > } > } > > // Calculate all lines through the point (x,y). > private void calc(int x, int y) { > double d; > int dIndex; > int index; > > for (int alpha = 0; alpha < cSteps; alpha++) { > d = y * cCosA[alpha] - x * cSinA[alpha]; > dIndex = (int) (d - cDMin); > index = dIndex * cSteps + alpha; > //Try > cHMatrix[index] = cHMatrix[index] + 1; > //Catch ex As Exception > // Debug.WriteLine(ex.ToString) > //End Try > } > } > > private void init() { > double angle; > > // Precalculation of sin and cos. > //ReDim cSinA(cSteps - 1) > //ReDim cCosA(cSteps - 1) > cSinA = new double[cSteps]; > cCosA = new double[cSteps]; > > for (int i = 0; i < cSteps; i++) { > angle = getAlpha(i) * Math.PI / 180.0D; > cSinA[i] = Math.sin(angle); > cCosA[i] = Math.cos(angle); > } > > // Range of d: > cDMin = -cBmp.getWidth(); > cDCount = (int) (2 * (cBmp.getWidth() + cBmp.getHeight()) / > cDStep); > cHMatrix = new int[cDCount * cSteps]; > } > > public double getAlpha(int index) { > return cAlphaStart + index * cAlphaStep; > } > } > > ------ > > /** > * Rotate a image by angle informed. > * @param image > * @param angle > * @param cx Center of width > * @param cy Center of height > * @return > */ > public static BufferedImage rotate(BufferedImage image, double angle, > int cx, int cy) { > int width = image.getWidth(null); > int height = image.getHeight(null); > > int minX, minY, maxX, maxY; > minX = minY = maxX = maxY = 0; > > int[] corners = { 0, 0, width, 0, width, height, 0, height }; > > double theta = Math.toRadians(angle); > > for (int i = 0; i < corners.length; i += 2) { > int x = (int) (Math.cos(theta) * (corners[i] - cx) - > Math.sin(theta) * (corners[i + 1] - cy) + cx); > int y = (int) (Math.sin(theta) * (corners[i] - cx) + > Math.cos(theta) * (corners[i + 1] - cy) + cy); > > if (x > maxX) { > maxX = x; > } > > if (x < minX) { > minX = x; > } > > if (y > maxY) { > maxY = y; > } > > if (y < minY) { > minY = y; > } > > } > > cx = (cx - minX); > cy = (cy - minY); > > int type = image.getType(); > if (type == 0) { > type = BufferedImage.TYPE_INT_RGB; > if (hasAlpha(image)) { > type = BufferedImage.TYPE_INT_ARGB; > } > } > > BufferedImage bi = new BufferedImage((maxX - minX), (maxY - minY), > type); > Graphics2D g2 = bi.createGraphics(); > g2.setRenderingHint(**RenderingHints.KEY_**INTERPOLATION, > RenderingHints.VALUE_**INTERPOLATION_BICUBIC); > > g2.setBackground(Color.white); > g2.fillRect(0, 0, bi.getWidth(), bi.getHeight()); > > AffineTransform at = new AffineTransform(); > at.rotate(theta, cx, cy); > > g2.setTransform(at); > g2.drawImage(image, -minX, -minY, null); > g2.dispose(); > > return bi; > } > > --- > > > Best regards. > > David > > > > > On 03/08/2013 03:55 PM, Anderson, Charles (DNR) wrote: > >> Carlos, >> >> I'm not sure what you mean by Deskew. >> >> To rotate manually: >> Use the angle tool on the toolbar to measure an angle, then Image > >> Transform > Rotate and enter the angle. >> >> You might also look at Plugins > Transform > and Interactive Affine, >> Interactive Perspective, or Landmark correspondence. Those might help if >> you had a reference image already in the target orientation. >> >> Charles >> >> -----Original Message----- >> From: ImageJ Interest Group [mailto:[hidden email]] On Behalf Of >> C.F.Scheidecker Antunes >> Sent: Friday, March 08, 2013 11:30 AM >> To: [hidden email] >> Subject: How to perform Deskew detection and also skew fix with imageJ >> >> Dear members, >> >> Does anyone has an example on how to determine deskew and also rotate the >> image to fix it with imageJ? >> >> I am new to the platform. >> >> Thanks in advance, >> >> Carlos. >> >> -- >> ImageJ mailing list: http://imagej.nih.gov/ij/list.**html<http://imagej.nih.gov/ij/list.html> >> >> -- >> ImageJ mailing list: http://imagej.nih.gov/ij/list.**html<http://imagej.nih.gov/ij/list.html> >> > > -- > ImageJ mailing list: http://imagej.nih.gov/ij/list.**html<http://imagej.nih.gov/ij/list.html> > -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Free forum by Nabble | Edit this page |