⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 recogniser.java

📁 Please read your package and describe it at least 40 bytes. System will automatically delete the di
💻 JAVA
字号:
// An abstract class with utility functions for Recognisers, plus a// bit of interface.//// Copyright (c) 2000 Markus Demleitner <mdemleitner@head-cfa.harvard.edu>//  This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,//  but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA//// tabsize=2import java.awt.*;import java.awt.image.*;import java.util.*;// an auxilliary class for handling grayscale images.  Since java// doesn't have unsigned bytes, the grayscales returned are between// 0 (black) and 127 (white).  For our purposes, that's still more // than enough.  The MSB is used by recognizers to mark stuff they've// already seen.class ByteGrabber implements ImageConsumer {		ImageProducer prod;	byte pixels[];	int px_w;	int readPixels = 0;	boolean errorOccurred = false;	public void setDimensions(int w,int h) 	{	}	public void setProperties(Hashtable<?,?> props) {}	public void setHints(int hintflags) {}	public void setColorModel(ColorModel model) {}	public synchronized byte[] retrievePixels(Image im, int w, int h)		throws Exception	{ 		this.prod = im.getSource();		this.px_w = w;		this.pixels = new byte[w*h];		int expectPixels = w*h;		this.prod.startProduction(this);		try {				while (this.readPixels<expectPixels && !this.errorOccurred) {				this.wait();			}		}	catch (InterruptedException e) {		}		if (this.errorOccurred)			throw new Exception("Could not retrieve pixels");		else			return this.pixels;	}	public synchronized void imageComplete(int s) 	{ 		switch (s) { 			case STATICIMAGEDONE:			case SINGLEFRAMEDONE:				this.errorOccurred = false;				break;			default:			case IMAGEERROR:			case IMAGEABORTED:				this.errorOccurred = true;				break;		}		this.prod.removeConsumer(this);		this.notifyAll();	}		public synchronized void setPixels(int x, int y, int w, int h,		ColorModel model, byte pix[], int off, int scansize)	{			for (int dy=0; dy<h; dy++) { 			int si=off+dy*scansize;			int di=(y+dy)*this.px_w+x;			for (int dx=0; dx<w; dx++,si++,di++) {				this.pixels[di] = (byte)(model.getRed(pix[si])/2);				this.readPixels++;			}		}	}	// I should go through the ColorModel, I guess, but for the	// forseeable future just masking should be ok.	public synchronized void setPixels(int x, int y, int w, int h,		ColorModel model, int pix[], int off, int scansize)	{			for (int dy=0; dy<h; dy++) { 			int si=off+dy*scansize;			int di=(y+dy)*px_w+x;			for (int dx=0; dx<w; dx++,si++,di++) {				this.pixels[di] = (byte)((pix[si]&0xff)/2);			}		}	}}public abstract class Recogniser extends Thread{ 	ImageWithPoints parent;	Image im;	int px_h, px_w, px_max;	byte pixels[];	Image deb_buf;	Graphics deb_gc;	boolean debug=false;	int blackThresh=110;	//everything below is considered black	int weightThresh=50;	//abandon line when weight drops below this	int axisLeft,axisRight,axisTop,axisBottom;	boolean stopMe=false;	boolean haveCoos=false;	RecogniserSettings settings;	// this function is used to communicate coordinates set by the user to	// the recogniser -- it should return true when it wants more coordinates	public abstract boolean putCoordinate(Point p);	// this function is called to do the actual recognising work	protected abstract void recogniseIt() throws Exception;	// this is a hook in which recognisers can do some analysis of	// the image up front -- it should return false or better raise an	// exception with an explanation if the recognition 	// cannot be performed	protected abstract boolean analyseIt() throws Exception;	public Recogniser(ImageWithPoints parent,RecogniserSettings settings)	{			this.parent = parent;		this.settings = settings;		blackThresh= settings.getIntProp("blackThresh");		weightThresh = settings.getIntProp("weightThresh");	}	// Computes the center of the black distribution on the vertical	// defined by the pixel index ind (i.e. somthing like x+y*px_w.)	// Returns a quadruple with the 	// cumulative weight (all black in column), the numerator	// for a weighted mean, and the maximum weight (the latter is	// used to dodge antialiasing artifacts), and the maximal y value	// considered (to avoid checking pixels twice)	// We really shouldn't be using Rectangles for that -- what was	// I thinking?	protected final Rectangle findCB(int ind)	{			int pos=0, cumweight=0;		int y=ind/px_w;		int weight;		int maxweight=0;		// walk down until white or end of picture		if (pixels[ind]<=blackThresh) { 			for (;ind<px_max; ind+=px_w, y++) {				if (pixels[ind]>blackThresh) { 					ind -= px_w;					y--;					break;				}			}		}		// back up if there was black all the way down		if (ind>=px_max) {			ind -= px_w;		}		// walk up again until we hit white, collecting distribution info		for (;ind>=0&&(pixels[ind]<=blackThresh); ind-=px_w, y--) {				weight = 127-pixels[ind];			if (weight>maxweight)				maxweight = weight;			pos += y*weight;			cumweight += weight;		}		if (maxweight>120)			maxweight = 127;  // That's a bad hack.  Feel free to remove it.				// Except that this seems to improve tracing of thin lines.		return new Rectangle(cumweight, pos, maxweight, y);	}	// as findCB, only in x direction	protected final int[] findxCB(int ind)	{	int pos=0, cumweight=0;		int x=ind%px_w, leftx;		int weight;		int maxweight=0;		int xlimit=ind-ind%px_w; // index of start of current line		// walk left until white or start of line		if (pixels[ind]<=blackThresh) {			for (;ind>xlimit; ind--, x--) {				if (pixels[ind]>blackThresh) { 					ind++;					x++;					break;				}			}		}		leftx = x;		xlimit = xlimit+px_w;  // index of start of line		// walk right until white or end of line		for (;ind<xlimit&&(pixels[ind]<=blackThresh); ind++, x++) {				weight = 127-pixels[ind];			if (weight>maxweight)				maxweight = weight;			pos += x*weight;			cumweight += weight;		}		if (maxweight>120)			maxweight = 127;  // That's a bad hack.  Feel free to remove it.				// Except that this seems to improve tracing of thin lines.		return new int[]{cumweight, pos, maxweight, leftx, x};	}	// start at starting point and try to identify where	// the line is going by checking the adjacent pixels.	protected boolean nextY(Point curpoint,int targy,int dx)	{	int y=curpoint.y;		int ind;		Rectangle res;		int maxweight=0,maxpos=0,maxblack=0;		int seenThrough=px_h;		int whiteCount=0;		int whiteLim=3;		int blackHeight;		int inity=y;		if (curpoint.x==px_w-1 || curpoint.x==0)			return false;		if (debug)			System.out.println("y target"+targy);		// walk to the bottom of the black zone in current column,		// accepting a little white in between.		for (ind=y*px_w+curpoint.x; ind<px_max; ind+=px_w, y++) {				if (pixels[ind]>blackThresh)				whiteCount++;			else				whiteCount = 0;			if (whiteCount>=whiteLim) {					ind -= px_w;				y--;				break;			}		}		// back up if we've left the image		while (ind>px_max) {			ind -= px_w;		}		// walk up again, looking at the column dx distant 		// (i.e., the left or right column) some black stuff		blackHeight = 0;		whiteCount = -1;		for (;ind>0; ind-=px_w, y--) {				// only run findCB if it hasn't already looked at these pixels			if (y>=seenThrough)  				continue;			if (pixels[ind]>blackThresh)				whiteCount++;			else				whiteCount = 0;			if (whiteCount>=whiteLim)				break;   // stop if there's too much white			blackHeight++;			if (pixels[ind+dx]<blackThresh) {					// Let's see where the center of the current blackness is				res = findCB(ind+dx);				seenThrough = res.height; // we don't want to check twice				if (res.width>maxblack || (res.width==maxblack && 						Math.abs(res.y/res.x-targy)<Math.abs(maxpos-targy))) {							maxweight = res.x;						maxpos = res.y/res.x;						maxblack = res.width;					}			}		}				if (y>inity)			System.out.println("Didn't reach start point at x="+curpoint.x);		if (blackHeight>px_h/2 || maxweight/100>px_h/2) {				if (debug)				System.out.println("Axis Alert");			return false;		}		if (maxweight>weightThresh) {				curpoint.y = maxpos;			return true;		}		return false;	}	// as nextY, only in x direction	protected boolean nextX(Point curpoint,int targx,int dy)	{	int x=curpoint.x;		int ind;		int res[];		int maxweight=0,maxpos=0,maxblack=0;		int seenThrough=0;		int whiteCount=0;		int whiteLim=3;		int blackWidth;		int initx=x;		dy *= px_w;		if (curpoint.y==px_h-1 || curpoint.y==0)			return false;		if (debug)			System.out.println("xt"+targx);		//walk to the left of the black zone		ind=curpoint.y*px_w+x;		int xlimit=ind%px_w;		for (;ind>xlimit;ind--,x--)		{	if (pixels[ind]>blackThresh)				whiteCount++;			else				whiteCount = 0;			if (whiteCount>=whiteLim)			{	ind++;				x++;				break;			}		}		// walk right again, looking at the column dy remote to find 		// some black stuff		xlimit = ind-ind%px_w+px_w;		blackWidth = 0;		whiteCount = -1;		for (;ind<xlimit;ind++,x++)		{	if (pixels[ind]>blackThresh)				whiteCount++;			else				whiteCount = 0;			if (whiteCount>=whiteLim)				break;			blackWidth++;			if (x<=seenThrough)				continue;			if (pixels[ind+dy]<blackThresh)			{	res = findxCB(ind+dy);				seenThrough = res[4];				if (res[2]>maxblack || (res[2]==maxblack && 						Math.abs(res[1]/res[0]-targx)<Math.abs(maxpos-targx)))					{	maxweight = res[0];						maxpos = res[1]/res[0];						maxblack = res[2];					}			}		}				if (x<initx)			System.out.println("Didn't reach start point at y="+curpoint.y);		if (blackWidth>px_w/2 || maxweight/100>px_w/2)		{	if (debug)				System.out.println("Axis Alert");			return false;		}		if (maxweight>weightThresh)		{	curpoint.x = maxpos;			return true;		}		return false;	}	private int xwidth(int ind)	{	int w=0;		int limLeft=ind-ind%px_w;		int limRight=limLeft+px_w;		while (pixels[ind]<blackThresh && ind>limLeft)			ind--;		ind++;		while (pixels[ind++]<blackThresh && ind<limRight)			w++;		return w;	}	// preloads the image, then	// tries to locate the axes and does some analysis of the image	// (much TBD), finally calls analyseIt, a hook in which individual	// recognisers can do their own preliminaria	protected boolean analyse() throws Exception	{		px_w = im.getWidth(parent);		px_h = im.getHeight(parent);		if (px_w==-1 || px_h==-1)			throw new Exception(				"Please wait until image \nis completely retrieved");		px_max = px_w*px_h;		pixels = new ByteGrabber().retrievePixels(im, px_w, px_h);		axisRight = px_w;		axisBottom = px_h;		axisLeft = 0;		axisTop = 0;		int ind;		// axis on the left		for (int ystart=px_h/6;ystart<px_h;ystart+=px_h/6) {				int stopat = ystart*px_w+px_w/4;			for (ind=ystart*px_w;ind<stopat;ind++) {					if (pixels[ind]<=blackThresh)					break;			}			if (pixels[ind]<=blackThresh) {					Rectangle r=findCB(ind);				if (r.width==0 || r.x/r.width<px_h/4)					r = findCB(++ind);				if (r.width!=0 && r.x/r.width>px_h/4) {						int width = 0;					for (;pixels[ind]<=blackThresh; ind++) {						width++;					}					axisLeft = ind%px_w+width;					break;				}			}		}		// bottom axis 		for (int xstart=px_w/6; xstart<px_w; xstart+=px_w/6) {				int stopat = (px_h-px_h/4)*px_w;			for (ind=xstart+(px_h-1)*px_w; ind>stopat; ind-=px_w) {					if (pixels[ind]<=blackThresh)					break;			}			if (pixels[ind]<=blackThresh) {					int w=xwidth(ind);				if (w<px_w/2) {						ind -= px_w;					w = xwidth(ind);				}				if (w>px_w/2) {						int height = 0;					for (;pixels[ind]<=blackThresh; ind-=px_w)						height++;					axisBottom = ind/px_w-height;					break;				}			}		}		// axis on right edge		int stopat = (px_h/2)*px_w-px_w/4;		for (ind=px_h/2*px_w-1; ind>stopat; ind--) {				if (pixels[ind]<=blackThresh)				break;		}		if (pixels[ind]<=blackThresh) {				Rectangle r=findCB(ind);			if (r.width==0 || r.x/r.width<px_h/4)				r = findCB(++ind);			if (r.width!=0 && r.x/r.width>px_h/4) {					int width = 0;				for (;pixels[ind]<=blackThresh;ind--)					width++;				axisRight = ind%px_w-width;			}		}		// the axis at the top		stopat = (px_h/4)*px_w;		for (ind=px_w/2;ind<stopat;ind+=px_w) {				if (pixels[ind]<=blackThresh)				break;		}		if (pixels[ind]<=blackThresh) {				int w=xwidth(ind);			if (w<px_w/2) {					ind += px_w;				w = xwidth(ind);			}			if (w>px_w/2) {					int height = 0;				for (;pixels[ind]<=blackThresh;ind+=px_w)					height++;				axisTop = ind/px_w+height;			}		}		if (debug)			System.out.println("detected axis"+axisLeft+" "+axisRight+" "+				axisTop+" "+axisBottom);		return analyseIt();	}		public synchronized void stopRecogniser()	{			stopMe = true;		this.notify();	}	protected synchronized boolean waitForCoos()	{ 		if (haveCoos)			return true;		try {				wait(); 		}	catch (InterruptedException e) {				return false; 		}		return true;	}	public void run()	{ 		try { 		try {		try {			if (!waitForCoos() || stopMe)				throw new Exception("Ignore");			im = parent.getRecImage();					if (analyse()) {					if (stopMe)					throw new Exception("Ignore");				recogniseIt();			}			else {				throw new Exception("Could not find start object");			}					if (debug)				System.out.println("Recogniser ends");		} catch (OutOfMemoryError e) { 			new AlertBox(parent.parent,"Recogniser failure",			"Out of memory.\nPlease try recognising at a lower resolution");}		} catch (Exception e) { 			if (!e.getMessage().equals("Ignore"))				if (e.getClass().toString().equals("class java.lang.Exception"))					new AlertBox(parent.parent,"Recogniser failure", e.getMessage());				else					new AlertBox(parent.parent,"Recogniser failure", e.toString()+						"\nYou shouldn't get such an insensible message.\n"+						"Please report how you managed to provoke it.");			e.printStackTrace();		}		} finally {				parent.recogniserStopped(); 		}	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -