Java Android洪水填充算法
有人知道一种迭代的、高效的洪水填充算法吗 或者有没有任何方法可以实现递归的Java Android洪水填充算法,java,android,image-processing,flood-fill,Java,Android,Image Processing,Flood Fill,有人知道一种迭代的、高效的洪水填充算法吗 或者有没有任何方法可以实现递归的泛洪填充算法而不出现堆栈溢出错误 试过一个@ 但我找不到一种处理黑白图像的方法 这个算法对我很有效 private void FloodFill(Bitmap bmp, Point pt, int targetColor, int replacementColor) { Queue<Point> q = new LinkedList<Point>(); q.add(pt);
泛洪填充算法而不出现堆栈溢出错误
试过一个@
但我找不到一种处理黑白图像的方法 这个算法对我很有效
private void FloodFill(Bitmap bmp, Point pt, int targetColor, int replacementColor)
{
Queue<Point> q = new LinkedList<Point>();
q.add(pt);
while (q.size() > 0) {
Point n = q.poll();
if (bmp.getPixel(n.x, n.y) != targetColor)
continue;
Point w = n, e = new Point(n.x + 1, n.y);
while ((w.x > 0) && (bmp.getPixel(w.x, w.y) == targetColor)) {
bmp.setPixel(w.x, w.y, replacementColor);
if ((w.y > 0) && (bmp.getPixel(w.x, w.y - 1) == targetColor))
q.add(new Point(w.x, w.y - 1));
if ((w.y < bmp.getHeight() - 1)
&& (bmp.getPixel(w.x, w.y + 1) == targetColor))
q.add(new Point(w.x, w.y + 1));
w.x--;
}
while ((e.x < bmp.getWidth() - 1)
&& (bmp.getPixel(e.x, e.y) == targetColor)) {
bmp.setPixel(e.x, e.y, replacementColor);
if ((e.y > 0) && (bmp.getPixel(e.x, e.y - 1) == targetColor))
q.add(new Point(e.x, e.y - 1));
if ((e.y < bmp.getHeight() - 1)
&& (bmp.getPixel(e.x, e.y + 1) == targetColor))
q.add(new Point(e.x, e.y + 1));
e.x++;
}
}
}
private void FloodFill(位图bmp、点pt、int targetColor、int replacementColor)
{
队列q=新的LinkedList();
q、 添加(pt);
而(q.size()>0){
n点=q.poll();
如果(bmp.getPixel(n.x,n.y)!=targetColor)
继续;
点w=n,e=新点(n.x+1,n.y);
而((w.x>0)和&(bmp.getPixel(w.x,w.y)==targetColor)){
bmp.setPixel(w.x,w.y,replacementColor);
if((w.y>0)&(bmp.getPixel(w.x,w.y-1)=targetColor))
q、 增加(新点(w.x,w.y-1));
如果((w.y0)&(bmp.getPixel(e.x,e.y-1)=targetColor))
q、 增加(新点(e.x,e.y-1));
如果((e.y
最好让FloodFill()
方法返回一个位图
对象。使其成为自定义视图
类的方法。您知道自定义的视图
类已经存在<代码>onDraw(画布)
方法。在onDraw(画布c)
中,使用FloodFill()
,如下所示:
//resize the picture that you want to fill to fit the whole display.
bitmap=Bitmap.createScaledBitmap(bitmap, canvas.getWidth(),canvas.getHeight(), true);
/*get the same bitmap flood fill it. we reassign the bit map to iself to keep it for the next and another flood fill
currently_selected_point is a variable/object of type Point.
use the Point object to save your onTouchEvent(Event event) finger coordinates.
I used the Color.RED as a replacement color.
the target color is the color of the selected point currently_selected_point.
*/
bitmap=FloodFill(bitmap, currently_selected_point, bitmap.getPixel(currently_selected_point.x, currently_selected_point.y), Color.RED);
canvas.drawBitmap(bitmap,0,0, paint);
有人将队列线性洪水填充算法移植到android。我试过了,速度很快
我修改了copyImage()
方法,该方法最初使用了作者未提供的名为Utilities的类
public class QueueLinearFloodFiller {
protected Bitmap image = null;
protected int[] tolerance = new int[] { 0, 0, 0 };
protected int width = 0;
protected int height = 0;
protected int[] pixels = null;
protected int fillColor = 0;
protected int[] startColor = new int[] { 0, 0, 0 };
protected boolean[] pixelsChecked;
protected Queue<FloodFillRange> ranges;
// Construct using an image and a copy will be made to fill into,
// Construct with BufferedImage and flood fill will write directly to
// provided BufferedImage
public QueueLinearFloodFiller(Bitmap img) {
copyImage(img);
}
public QueueLinearFloodFiller(Bitmap img, int targetColor, int newColor) {
useImage(img);
setFillColor(newColor);
setTargetColor(targetColor);
}
public void setTargetColor(int targetColor) {
startColor[0] = Color.red(targetColor);
startColor[1] = Color.green(targetColor);
startColor[2] = Color.blue(targetColor);
}
public int getFillColor() {
return fillColor;
}
public void setFillColor(int value) {
fillColor = value;
}
public int[] getTolerance() {
return tolerance;
}
public void setTolerance(int[] value) {
tolerance = value;
}
public void setTolerance(int value) {
tolerance = new int[] { value, value, value };
}
public Bitmap getImage() {
return image;
}
public void copyImage(Bitmap img) {
// Copy data from provided Image to a BufferedImage to write flood fill
// to, use getImage to retrieve
// cache data in member variables to decrease overhead of property calls
width = img.getWidth();
height = img.getHeight();
image = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(image);
canvas.drawBitmap(img, 0, 0, null);
pixels = new int[width * height];
image.getPixels(pixels, 0, width, 1, 1, width - 1, height - 1);
}
public void useImage(Bitmap img) {
// Use a pre-existing provided BufferedImage and write directly to it
// cache data in member variables to decrease overhead of property calls
width = img.getWidth();
height = img.getHeight();
image = img;
pixels = new int[width * height];
image.getPixels(pixels, 0, width, 1, 1, width - 1, height - 1);
}
protected void prepare() {
// Called before starting flood-fill
pixelsChecked = new boolean[pixels.length];
ranges = new LinkedList<FloodFillRange>();
}
// Fills the specified point on the bitmap with the currently selected fill
// color.
// int x, int y: The starting coords for the fill
public void floodFill(int x, int y) {
// Setup
prepare();
if (startColor[0] == 0) {
// ***Get starting color.
int startPixel = pixels[(width * y) + x];
startColor[0] = (startPixel >> 16) & 0xff;
startColor[1] = (startPixel >> 8) & 0xff;
startColor[2] = startPixel & 0xff;
}
// ***Do first call to floodfill.
LinearFill(x, y);
// ***Call floodfill routine while floodfill ranges still exist on the
// queue
FloodFillRange range;
while (ranges.size() > 0) {
// **Get Next Range Off the Queue
range = ranges.remove();
// **Check Above and Below Each Pixel in the Floodfill Range
int downPxIdx = (width * (range.Y + 1)) + range.startX;
int upPxIdx = (width * (range.Y - 1)) + range.startX;
int upY = range.Y - 1;// so we can pass the y coord by ref
int downY = range.Y + 1;
for (int i = range.startX; i <= range.endX; i++) {
// *Start Fill Upwards
// if we're not above the top of the bitmap and the pixel above
// this one is within the color tolerance
if (range.Y > 0 && (!pixelsChecked[upPxIdx])
&& CheckPixel(upPxIdx))
LinearFill(i, upY);
// *Start Fill Downwards
// if we're not below the bottom of the bitmap and the pixel
// below this one is within the color tolerance
if (range.Y < (height - 1) && (!pixelsChecked[downPxIdx])
&& CheckPixel(downPxIdx))
LinearFill(i, downY);
downPxIdx++;
upPxIdx++;
}
}
image.setPixels(pixels, 0, width, 1, 1, width - 1, height - 1);
}
// Finds the furthermost left and right boundaries of the fill area
// on a given y coordinate, starting from a given x coordinate, filling as
// it goes.
// Adds the resulting horizontal range to the queue of floodfill ranges,
// to be processed in the main loop.
// int x, int y: The starting coords
protected void LinearFill(int x, int y) {
// ***Find Left Edge of Color Area
int lFillLoc = x; // the location to check/fill on the left
int pxIdx = (width * y) + x;
while (true) {
// **fill with the color
pixels[pxIdx] = fillColor;
// **indicate that this pixel has already been checked and filled
pixelsChecked[pxIdx] = true;
// **de-increment
lFillLoc--; // de-increment counter
pxIdx--; // de-increment pixel index
// **exit loop if we're at edge of bitmap or color area
if (lFillLoc < 0 || (pixelsChecked[pxIdx]) || !CheckPixel(pxIdx)) {
break;
}
}
lFillLoc++;
// ***Find Right Edge of Color Area
int rFillLoc = x; // the location to check/fill on the left
pxIdx = (width * y) + x;
while (true) {
// **fill with the color
pixels[pxIdx] = fillColor;
// **indicate that this pixel has already been checked and filled
pixelsChecked[pxIdx] = true;
// **increment
rFillLoc++; // increment counter
pxIdx++; // increment pixel index
// **exit loop if we're at edge of bitmap or color area
if (rFillLoc >= width || pixelsChecked[pxIdx] || !CheckPixel(pxIdx)) {
break;
}
}
rFillLoc--;
// add range to queue
FloodFillRange r = new FloodFillRange(lFillLoc, rFillLoc, y);
ranges.offer(r);
}
// Sees if a pixel is within the color tolerance range.
protected boolean CheckPixel(int px) {
int red = (pixels[px] >>> 16) & 0xff;
int green = (pixels[px] >>> 8) & 0xff;
int blue = pixels[px] & 0xff;
return (red >= (startColor[0] - tolerance[0])
&& red <= (startColor[0] + tolerance[0])
&& green >= (startColor[1] - tolerance[1])
&& green <= (startColor[1] + tolerance[1])
&& blue >= (startColor[2] - tolerance[2]) && blue <= (startColor[2] + tolerance[2]));
}
// Represents a linear range to be filled and branched from.
protected class FloodFillRange {
public int startX;
public int endX;
public int Y;
public FloodFillRange(int startX, int endX, int y) {
this.startX = startX;
this.endX = endX;
this.Y = y;
}
}
}
我加快了上面的算法。
使用getPixels()
和setPixels()
而不是反复调用getPixel()
但是这里有一个问题。
这个算法为数组int[bmp.width*bmp.height]
使用了更多的内存空间
private void floodFill_array(Bitmap bmp, Point pt, int targetColor, int replacementColor)
{
if(targetColor == replacementColor)
return;
int width, height;
int[] arrPixels;
width = bmp.getWidth();
height = bmp.getHeight();
arrPixels = new int[width*height];
bmp.getPixels(arrPixels, 0, width, 0, 0, width, height);
Queue<Point> q = new LinkedList<Point>();
q.add(pt);
while (q.size() > 0) {
Point n = q.poll();
if (arrPixels[width*n.y + n.x] != targetColor)
continue;
Point w = n, e = new Point(n.x + 1, n.y);
while ((w.x > 0) && (arrPixels[width*w.y + w.x] == targetColor)) {
arrPixels[width*w.y + w.x] = replacementColor; // setPixel
if ((w.y > 0) && (arrPixels[width*(w.y-1) + w.x] == targetColor))
q.add(new Point(w.x, w.y - 1));
if ((w.y < height - 1)
&& (arrPixels[width*(w.y+1) + w.x] == targetColor))
q.add(new Point(w.x, w.y + 1));
w.x--;
}
while ((e.x < width - 1)
&& (arrPixels[width*e.y + e.x] == targetColor)) {
arrPixels[width*e.y + e.x] = replacementColor; // setPixel
if ((e.y > 0) && (arrPixels[width*(e.y-1) + e.x] == targetColor))
q.add(new Point(e.x, e.y - 1));
if ((e.y < height - 1)
&& (arrPixels[width*(e.y+1) + e.x] == targetColor))
q.add(new Point(e.x, e.y + 1));
e.x++;
}
}
bmp.setPixels(arrPixels, 0, width, 0, 0, width, height);
}
private void floodFill_数组(位图bmp、点pt、int targetColor、int replacementColor)
{
if(targetColor==replacementColor)
返回;
int宽度、高度;
整数像素;
宽度=bmp.getWidth();
height=bmp.getHeight();
arrPixels=新整数[宽度*高度];
getPixels(像素,0,宽度,0,0,宽度,高度);
队列q=新的LinkedList();
q、 添加(pt);
而(q.size()>0){
n点=q.poll();
if(arrPixels[width*n.y+n.x]!=targetColor)
继续;
点w=n,e=新点(n.x+1,n.y);
而((w.x>0)和&(arrpolxels[width*w.y+w.x]==targetColor)){
arrPixels[width*w.y+w.x]=replacementColor;//设置像素
如果((w.y>0)和&(arrPixels[width*(w.y-1)+w.x]==targetColor))
q、 增加(新点(w.x,w.y-1));
如果((宽y<高度-1)
&&(arrPixels[宽度*(w.y+1)+w.x]==目标颜色))
q、 添加(新点(w.x,w.y+1));
w、 x--;
}
而((e.x<宽度-1)
&&(arrPixels[宽度*e.y+e.x]==targetColor)){
arrPixels[width*e.y+e.x]=replacementColor;//设置像素
如果((e.y>0)和&(arrPixels[width*(e.y-1)+e.x]==targetColor))
q、 增加(新点(e.x,e.y-1));
如果((e.y<高度-1)
&&(arrPixels[宽度*(e.y+1)+e.x]==目标颜色))
q、 添加(新点(e.x,e.y+1));
e、 x++;
}
}
设置像素(像素,0,宽度,0,0,宽度,高度);
}
如果要使用“公差”选项,请使用下面的代码
int minR, maxR, minG, maxG, minB, maxB; // instance values
private void floodFill_array(Bitmap bmp, Point pt, int targetColor, int replacementColor, int tolerance)
{
if(targetColor == replacementColor)
return;
/* tolerable values */
minR = ((targetColor & 0xFF0000) >> 16) - tolerance;
if(minR < 0) minR = 0;
else minR = minR << 16;
maxR = ((targetColor & 0xFF0000) >> 16) + tolerance;
if(maxR > 0xFF) maxR = 0xFF0000;
else maxR = maxR << 16;
minG = ((targetColor & 0x00FF00) >> 8) - tolerance;
if(minG < 0) minG = 0;
else minG = minG << 8;
maxG = ((targetColor & 0x00FF00) >> 8) + tolerance;
if(maxG > 0xFF) maxG = 0x00FF00;
else maxG = maxG << 8;
minB = (targetColor & 0x0000FF) - tolerance;
if(minB < 0) minB = 0;
maxB = (targetColor & 0x0000FF) + tolerance;
if(maxB > 0xFF) maxB = 0x0000FF;
/* tolerable values */
int width, height;
int[] arrPixels;
width = bmp.getWidth();
height = bmp.getHeight();
arrPixels = new int[width*height];
bmp.getPixels(arrPixels, 0, width, 0, 0, width, height);
Queue<Point> q = new LinkedList<Point>();
q.add(pt);
while (q.size() > 0) {
Point n = q.poll();
if(!isTolerable(arrPixels[width*n.y + n.x]))
continue;
Point w = n, e = new Point(n.x + 1, n.y);
while ((w.x > 0) && isTolerable(arrPixels[width*w.y + w.x])) {
arrPixels[width*w.y + w.x] = replacementColor; // setPixel
if ((w.y > 0) && isTolerable(arrPixels[width*(w.y-1) + w.x]))
q.add(new Point(w.x, w.y - 1));
if ((w.y < height - 1) && isTolerable(arrPixels[width*(w.y+1) + w.x]))
q.add(new Point(w.x, w.y + 1));
w.x--;
}
while ((e.x < width - 1) && isTolerable(arrPixels[width*e.y + e.x])) {
arrPixels[width*e.y + e.x] = replacementColor; // setPixel
if ((e.y > 0) && isTolerable(arrPixels[width*(e.y-1) + e.x]))
q.add(new Point(e.x, e.y - 1));
if ((e.y < height - 1) && isTolerable(arrPixels[width*(e.y+1) + e.x]))
q.add(new Point(e.x, e.y + 1));
e.x++;
}
}
bmp.setPixels(arrPixels, 0, width, 0, 0, width, height);
}
/**
* If the passed color is tolerable, return true.
*/
private boolean isTolerable(int currentColor){
int r = currentColor & 0xFF0000;
int g = currentColor & 0x00FF00;
int b = currentColor & 0x0000FF;
if(r<minR || r>maxR || g<minG || g>maxG || b<minB || b>maxB)
return false; // less than or grater than tolerable values
else
return true;
}
int minR,maxR,minG,maxG,minB,maxB;//实例值
专用空白泛光填充数组(位图bmp、点pt、int targetColor、int replacementColor、int容差)
{
if(targetColor==replacementColor)
返回;
/*容许值*/
minR=((targetColor&0xFF0000)>>16)-公差;
如果(minR<0)minR=0;
否则minR=minR>16)+公差;
如果(maxR>0xFF)maxR=0xFF0000;
否则maxR=maxR>8)-公差;
如果(minG<0)minG=0;
否则明=明>8)+公差;
如果(maxG>0xFF)maxG=0x00FF00;
else maxG=maxG 0xFF)maxB=0x0000FF;
/*容许值*/
int宽度、高度;
整数像素;
宽度=bmp.getWidth();
height=bmp.getHeight();
arrPixels=新整数[宽度*高度];
getPixels(像素,0,宽度,0,0,宽度,高度);
队列q=新的LinkedList();
q、 添加(pt);
而(q.size()>0){
n点=q.poll();
如果(!isTolerable(arrPixels[width*n.y+n.x]))
继续;
点w=n,e=新点(n.x+1,n.y);
while((w.x>0)和&isTolerable(arrPixels[width*w.y+w.x])){
arrPixels[width*w.y+w.x]=replacementColor;//设置像素
if((w.y>0)和&isTolerable(arr像素[宽度*(w.y-1)+w.x]))
q、 增加(新点(w.x,w.y-1));
如果((宽y<高-1)和&isTolerable(arrPixels[宽度*(宽y+1)+宽x]))
q、 添加(新点(w.x,w.y+1));
w、 x--;
}
而((e.x0)&&i可容忍(arrpicxels[宽度*(e.y-1)+e.x]))
int minR, maxR, minG, maxG, minB, maxB; // instance values
private void floodFill_array(Bitmap bmp, Point pt, int targetColor, int replacementColor, int tolerance)
{
if(targetColor == replacementColor)
return;
/* tolerable values */
minR = ((targetColor & 0xFF0000) >> 16) - tolerance;
if(minR < 0) minR = 0;
else minR = minR << 16;
maxR = ((targetColor & 0xFF0000) >> 16) + tolerance;
if(maxR > 0xFF) maxR = 0xFF0000;
else maxR = maxR << 16;
minG = ((targetColor & 0x00FF00) >> 8) - tolerance;
if(minG < 0) minG = 0;
else minG = minG << 8;
maxG = ((targetColor & 0x00FF00) >> 8) + tolerance;
if(maxG > 0xFF) maxG = 0x00FF00;
else maxG = maxG << 8;
minB = (targetColor & 0x0000FF) - tolerance;
if(minB < 0) minB = 0;
maxB = (targetColor & 0x0000FF) + tolerance;
if(maxB > 0xFF) maxB = 0x0000FF;
/* tolerable values */
int width, height;
int[] arrPixels;
width = bmp.getWidth();
height = bmp.getHeight();
arrPixels = new int[width*height];
bmp.getPixels(arrPixels, 0, width, 0, 0, width, height);
Queue<Point> q = new LinkedList<Point>();
q.add(pt);
while (q.size() > 0) {
Point n = q.poll();
if(!isTolerable(arrPixels[width*n.y + n.x]))
continue;
Point w = n, e = new Point(n.x + 1, n.y);
while ((w.x > 0) && isTolerable(arrPixels[width*w.y + w.x])) {
arrPixels[width*w.y + w.x] = replacementColor; // setPixel
if ((w.y > 0) && isTolerable(arrPixels[width*(w.y-1) + w.x]))
q.add(new Point(w.x, w.y - 1));
if ((w.y < height - 1) && isTolerable(arrPixels[width*(w.y+1) + w.x]))
q.add(new Point(w.x, w.y + 1));
w.x--;
}
while ((e.x < width - 1) && isTolerable(arrPixels[width*e.y + e.x])) {
arrPixels[width*e.y + e.x] = replacementColor; // setPixel
if ((e.y > 0) && isTolerable(arrPixels[width*(e.y-1) + e.x]))
q.add(new Point(e.x, e.y - 1));
if ((e.y < height - 1) && isTolerable(arrPixels[width*(e.y+1) + e.x]))
q.add(new Point(e.x, e.y + 1));
e.x++;
}
}
bmp.setPixels(arrPixels, 0, width, 0, 0, width, height);
}
/**
* If the passed color is tolerable, return true.
*/
private boolean isTolerable(int currentColor){
int r = currentColor & 0xFF0000;
int g = currentColor & 0x00FF00;
int b = currentColor & 0x0000FF;
if(r<minR || r>maxR || g<minG || g>maxG || b<minB || b>maxB)
return false; // less than or grater than tolerable values
else
return true;
}
protected int[] tolerance = new int[] { 0, 0, 0, 0 };
protected int[] startColor = new int[] { 0, 0, 0, 0 };
public void setTargetColor(int targetColor) {
/*Same as before....*/
startColor[3] = Color.alpha(targetColor);
}
public void setTolerance(int value) {
tolerance = new int[] { value, value, value, value };
}
protected boolean CheckPixel(int px) {
int red = (pixels[px] >>> 16) & 0xff;
int green = (pixels[px] >>> 8) & 0xff;
int blue = pixels[px] & 0xff;
int alpha = (Color.alpha(pixels[px]));
return (red >= (startColor[0] - tolerance[0]) && red <= (startColor[0] + tolerance[0])
&& green >= (startColor[1] - tolerance[1]) && green <= (startColor[1] + tolerance[1])
&& blue >= (startColor[2] - tolerance[2]) && blue <= (startColor[2] + tolerance[2])
&& alpha >= (startColor[3] - tolerance[3]) && alpha <= (startColor[3] + tolerance[3]));
}