9
A
回答
1
package ac.essex.ooechs.imaging.commons.edge.hough;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.util.Vector;
import java.io.File;
/**
* <p/>
* Java Implementation of the Hough Transform.<br />
* Used for finding straight lines in an image.<br />
* by Olly Oechsle
* </p>
* <p/>
* Note: This class is based on original code from:<br />
* <a href="http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm">http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm</a>
* </p>
* <p/>
* If you represent a line as:<br />
* x cos(theta) + y sin (theta) = r
* </p>
* <p/>
* ... and you know values of x and y, you can calculate all the values of r by going through
* all the possible values of theta. If you plot the values of r on a graph for every value of
* theta you get a sinusoidal curve. This is the Hough transformation.
* </p>
* <p/>
* The hough tranform works by looking at a number of such x,y coordinates, which are usually
* found by some kind of edge detection. Each of these coordinates is transformed into
* an r, theta curve. This curve is discretised so we actually only look at a certain discrete
* number of theta values. "Accumulator" cells in a hough array along this curve are incremented
* for X and Y coordinate.
* </p>
* <p/>
* The accumulator space is plotted rectangularly with theta on one axis and r on the other.
* Each point in the array represents an (r, theta) value which can be used to represent a line
* using the formula above.
* </p>
* <p/>
* Once all the points have been added should be full of curves. The algorithm then searches for
* local peaks in the array. The higher the peak the more values of x and y crossed along that curve,
* so high peaks give good indications of a line.
* </p>
*
* @author Olly Oechsle, University of Essex
*/
public class HoughTransform extends Thread {
public static void main(String[] args) throws Exception {
String filename = "/home/ooechs/Desktop/vase.png";
// load the file using Java's imageIO library
BufferedImage image = javax.imageio.ImageIO.read(new File(filename));
// create a hough transform object with the right dimensions
HoughTransform h = new HoughTransform(image.getWidth(), image.getHeight());
// add the points from the image (or call the addPoint method separately if your points are not in an image
h.addPoints(image);
// get the lines out
Vector<HoughLine> lines = h.getLines(30);
// draw the lines back onto the image
for (int j = 0; j < lines.size(); j++) {
HoughLine line = lines.elementAt(j);
line.draw(image, Color.RED.getRGB());
}
}
// The size of the neighbourhood in which to search for other local maxima
final int neighbourhoodSize = 4;
// How many discrete values of theta shall we check?
final int maxTheta = 180;
// Using maxTheta, work out the step
final double thetaStep = Math.PI/maxTheta;
// the width and height of the image
protected int width, height;
// the hough array
protected int[][] houghArray;
// the coordinates of the centre of the image
protected float centerX, centerY;
// the height of the hough array
protected int houghHeight;
// double the hough height (allows for negative numbers)
protected int doubleHeight;
// the number of points that have been added
protected int numPoints;
// cache of values of sin and cos for different theta values. Has a significant performance improvement.
private double[] sinCache;
private double[] cosCache;
/**
* Initialises the hough transform. The dimensions of the input image are needed
* in order to initialise the hough array.
*
* @param width The width of the input image
* @param height The height of the input image
*/
public HoughTransform(int width, int height) {
this.width = width;
this.height = height;
initialise();
}
/**
* Initialises the hough array. Called by the constructor so you don't need to call it
* yourself, however you can use it to reset the transform if you want to plug in another
* image (although that image must have the same width and height)
*/
public void initialise() {
// Calculate the maximum height the hough array needs to have
houghHeight = (int) (Math.sqrt(2) * Math.max(height, width))/2;
// Double the height of the hough array to cope with negative r values
doubleHeight = 2 * houghHeight;
// Create the hough array
houghArray = new int[maxTheta][doubleHeight];
// Find edge points and vote in array
centerX = width/2;
centerY = height/2;
// Count how many points there are
numPoints = 0;
// cache the values of sin and cos for faster processing
sinCache = new double[maxTheta];
cosCache = sinCache.clone();
for (int t = 0; t < maxTheta; t++) {
double realTheta = t * thetaStep;
sinCache[t] = Math.sin(realTheta);
cosCache[t] = Math.cos(realTheta);
}
}
/**
* Adds points from an image. The image is assumed to be greyscale black and white, so all pixels that are
* not black are counted as edges. The image should have the same dimensions as the one passed to the constructor.
*/
public void addPoints(BufferedImage image) {
// Now find edge points and update the hough array
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
// Find non-black pixels
if ((image.getRGB(x, y) & 0x000000ff) != 0) {
addPoint(x, y);
}
}
}
}
/**
* Adds a single point to the hough transform. You can use this method directly
* if your data isn't represented as a buffered image.
*/
public void addPoint(int x, int y) {
// Go through each value of theta
for (int t = 0; t < maxTheta; t++) {
//Work out the r values for each theta step
int r = (int) (((x - centerX) * cosCache[t]) + ((y - centerY) * sinCache[t]));
// this copes with negative values of r
r += houghHeight;
if (r < 0 || r >= doubleHeight) continue;
// Increment the hough array
houghArray[t][r]++;
}
numPoints++;
}
/**
* Once points have been added in some way this method extracts the lines and returns them as a Vector
* of HoughLine objects, which can be used to draw on the
*
* @param percentageThreshold The percentage threshold above which lines are determined from the hough array
*/
public Vector<HoughLine> getLines(int threshold) {
// Initialise the vector of lines that we'll return
Vector<HoughLine> lines = new Vector<HoughLine>(20);
// Only proceed if the hough array is not empty
if (numPoints == 0) return lines;
// Search for local peaks above threshold to draw
for (int t = 0; t < maxTheta; t++) {
loop:
for (int r = neighbourhoodSize; r < doubleHeight - neighbourhoodSize; r++) {
// Only consider points above threshold
if (houghArray[t][r] > threshold) {
int peak = houghArray[t][r];
// Check that this peak is indeed the local maxima
for (int dx = -neighbourhoodSize; dx <= neighbourhoodSize; dx++) {
for (int dy = -neighbourhoodSize; dy <= neighbourhoodSize; dy++) {
int dt = t + dx;
int dr = r + dy;
if (dt < 0) dt = dt + maxTheta;
else if (dt >= maxTheta) dt = dt - maxTheta;
if (houghArray[dt][dr] > peak) {
// found a bigger point nearby, skip
continue loop;
}
}
}
// calculate the true value of theta
double theta = t * thetaStep;
// add the line to the vector
lines.add(new HoughLine(theta, r));
}
}
}
return lines;
}
/**
* Gets the highest value in the hough array
*/
public int getHighestValue() {
int max = 0;
for (int t = 0; t < maxTheta; t++) {
for (int r = 0; r < doubleHeight; r++) {
if (houghArray[t][r] > max) {
max = houghArray[t][r];
}
}
}
return max;
}
/**
* Gets the hough array as an image, in case you want to have a look at it.
*/
public BufferedImage getHoughArrayImage() {
int max = getHighestValue();
BufferedImage image = new BufferedImage(maxTheta, doubleHeight, BufferedImage.TYPE_INT_ARGB);
for (int t = 0; t < maxTheta; t++) {
for (int r = 0; r < doubleHeight; r++) {
double value = 255 * ((double) houghArray[t][r])/max;
int v = 255 - (int) value;
int c = new Color(v, v, v).getRGB();
image.setRGB(t, r, c);
}
}
return image;
}
}
來源:http://vase.essex.ac.uk/software/HoughTransform/HoughTransform.java.html
2
一個簡單的分割算法可以幫助你。該算法繼承人如何工作的:
- 掃描像素從左至右 記錄第一 黑色(無論您 線的顏色)像素的位置。
- 進行這個過程 除非你找到一個完整的掃描時 你找不到黑色像素。 也要記錄這個位置。
- 我們是 只是感興趣的Y位置 在這裏。現在使用這個Y位置 水平分割圖像。
- 現在 我們將做同樣的過程 但這次我們是在我們剛剛創建的段(在 一次一列)要掃描 從上到下。
- 這次我們感興趣的是X 職位。
- 所以最後我們得到每一行 行的範圍,或者你可以說每個行都有一個 包圍盒。
- 這些邊界框的總數 是行數。
您可以根據您的需要在算法中做很多優化。
+0
+1很好的解釋。這用於OCR以及字符分割。 – 2010-10-14 12:16:09
+0
是否有Java API來實現這一目標? – Sid 2010-10-14 12:36:47
0
這取決於它們看起來像多少。
- 把圖像以1位(黑色和白色)以保留線和帶來的背景的純白色
- 或許做簡單的清理像斑點去除(去除任何小的黑色成分)的方法。
然後,
- 查找黑像素
- 使用洪水填充算法,以發現其程度
- 查看該形狀滿足標準,作爲一個線路(lineCount ++若有)
- 刪除它
- 重複此操作,直到沒有黑色像素
在很大程度上取決於你做的有多好#3,只是在這一節的一些想法
- 使用霍夫檢查你有一條線,而且它是垂直的(ISH)
- (後# 1)將其旋轉到垂直和檢查它的寬/高比
1
我實現使用Marvin Framework簡單的解決方案(必須得到改善),該發現的垂直線的開始和結束點,並打印線的總數找到。
方法:
- 二值化利用給定的閾值的圖像。
- 對於每個像素,如果是黑色(固體),試圖找到一條垂直線
- 保存的X,Y的起點和終點
- 線的最小lenght的?這是一條可以接受的路線!
- 用紅色打印起點,用綠色打印終點。
輸出圖像顯示如下:
的程序輸出:
Vertical line fount at: (74,9,70,33)
Vertical line fount at: (113,9,109,31)
Vertical line fount at: (80,10,76,32)
Vertical line fount at: (137,11,133,33)
Vertical line fount at: (163,11,159,33)
Vertical line fount at: (184,11,180,33)
Vertical line fount at: (203,11,199,33)
Vertical line fount at: (228,11,224,33)
Vertical line fount at: (248,11,244,33)
Vertical line fount at: (52,12,50,33)
Vertical line fount at: (145,13,141,35)
Vertical line fount at: (173,13,169,35)
Vertical line fount at: (211,13,207,35)
Vertical line fount at: (94,14,90,36)
Vertical line fount at: (238,14,236,35)
Vertical line fount at: (130,16,128,37)
Vertical line fount at: (195,16,193,37)
Vertical lines total: 17
最後,源代碼:
import java.awt.Color;
import java.awt.Point;
import marvin.image.MarvinImage;
import marvin.io.MarvinImageIO;
import marvin.plugin.MarvinImagePlugin;
import marvin.util.MarvinPluginLoader;
public class VerticalLineCounter {
private MarvinImagePlugin threshold = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.thresholding");
public VerticalLineCounter(){
// Binarize
MarvinImage image = MarvinImageIO.loadImage("./res/lines.jpg");
MarvinImage binImage = image.clone();
threshold.setAttribute("threshold", 127);
threshold.process(image, binImage);
// Find lines and save an output image
MarvinImage imageOut = findVerticalLines(binImage, image);
MarvinImageIO.saveImage(imageOut, "./res/lines_out.png");
}
private MarvinImage findVerticalLines(MarvinImage binImage, MarvinImage originalImage){
MarvinImage imageOut = originalImage.clone();
boolean[][] processedPixels = new boolean[binImage.getWidth()][binImage.getHeight()];
int color;
Point endPoint;
int totalLines=0;
for(int y=0; y<binImage.getHeight(); y++){
for(int x=0; x<binImage.getWidth(); x++){
if(!processedPixels[x][y]){
color = binImage.getIntColor(x, y);
// Black?
if(color == 0xFF000000){
endPoint = getEndOfLine(x,y,binImage,processedPixels);
// Line lenght threshold
if(endPoint.x - x > 5 || endPoint.y - y > 5){
imageOut.fillRect(x-2, y-2, 5, 5, Color.red);
imageOut.fillRect(endPoint.x-2, endPoint.y-2, 5, 5, Color.green);
totalLines++;
System.out.println("Vertical line fount at: ("+x+","+y+","+endPoint.x+","+endPoint.y+")");
}
}
}
processedPixels[x][y] = true;
}
}
System.out.println("Vertical lines total: "+totalLines);
return imageOut;
}
private Point getEndOfLine(int x, int y, MarvinImage image, boolean[][] processedPixels){
int xC=x;
int cY=y;
while(true){
processedPixels[xC][cY] = true;
processedPixels[xC-1][cY] = true;
processedPixels[xC-2][cY] = true;
processedPixels[xC-3][cY] = true;
processedPixels[xC+1][cY] = true;
processedPixels[xC+2][cY] = true;
processedPixels[xC+3][cY] = true;
if(getSafeIntColor(xC,cY,image) < 0xFF000000){
// nothing
}
else if(getSafeIntColor(xC-1,cY,image) == 0xFF000000){
xC = xC-2;
}
else if(getSafeIntColor(xC-2,cY,image) == 0xFF000000){
xC = xC-3;
}
else if(getSafeIntColor(xC+1,cY,image) == 0xFF000000){
xC = xC+2;
}
else if(getSafeIntColor(xC+2,cY,image) == 0xFF000000){
xC = xC+3;
}
else{
return new Point(xC, cY);
}
cY++;
}
}
private int getSafeIntColor(int x, int y, MarvinImage image){
if(x >= 0 && x < image.getWidth() && y >= 0 && y < image.getHeight()){
return image.getIntColor(x, y);
}
return -1;
}
public static void main(String args[]){
new VerticalLineCounter();
System.exit(0);
}
}
相關問題
- 1. 計數水平和垂直線圖像
- 2. 垂直計算列
- 3. 計算垂直和水平直方圖
- 4. 垂直鏡像Java中的圖像
- 5. 計算垂直於另一條線的中點的線
- 6. 響應HTML - 垂直線跨圖像
- 7. 計算用Java(圖像分析)形狀取向
- 8. 劃分垂直和水平線/視圖
- 9. HTML垂直分隔線
- 10. CSS垂直分隔線
- 11. 垂直分隔線CSS
- 12. 垂直對齊圖像中的分區
- 13. 垂直居中風格鏈接圖像左側的分隔線
- 14. 如何檢測圖像中的部分垂直/水平線?
- 15. 垂直黑線
- 16. 從分散點計算直線
- 17. 如何將此圖像合併到圖像的垂直線隱藏部分?
- 18. Python - 計算圖像的直方圖
- 19. 用repa計算圖像直方圖
- 20. JFreeChart - 垂直折線圖
- 21. 垂直Epander像垂直頭
- 22. 計算流數據上的直方圖 - 在線直方圖計算
- 23. dygraph垂直線
- 24. 吳的抗鋸齒算法,垂直線
- 25. 計算積分圖像
- 26. 計算圖像積分
- 27. 計算SVG文本的垂直高度
- 28. 垂直線的EditText
- 29. 直方圖中的垂直線與pyplot
- 30. 直方圖沒有垂直線
HTTP:// EN .wikipedia.org/wiki/Hough_transform這可能有幫助,順便說一句+1 – 2010-10-14 11:33:49