如何在特定区域填充图像颜色?

16

我想在基于Paint的应用程序中为白色区域填充颜色,所以请给我建议如何完成这项工作。

输入图像描述


5
请查看经典的泛洪填充算法:http://en.wikipedia.org/wiki/Flood_fill - Jave
你好, 这里是获取图像点的链接。意思是只获取图像的实际部分并消除透明部分,但我无法限定区域。 - Hiren Dabhi
1
非常感谢Jave提供的泛洪算法信息。 - Hardik Gajjar
@misha:我正在使用JAVA语言开发Android平台。 - Hardik Gajjar
我想用画笔填充它...当用户触摸移动时...你能帮我吗? - Alfa
显示剩余2条评论
4个回答

19

我用泛洪算法找到了解决方案

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++;
    }
}}

在Android中进行泛洪填充:

请参考这个FloodFill


不错,但如果我只是将这个算法添加到我的Android应用程序中,如果我调用FloodFill函数(带有相应的属性),那么它会工作吗?在这个函数中我需要给出什么样的点属性? - Shreyash Mahajan
谢谢@Hardik,这确实是一个很好的算法。但对于安卓手机来说,它似乎非常慢。你知道其他的泛洪填充方法吗? - Satyajitsinh Raijada
1
有人能解释一下如何提供目标颜色和替换颜色以及使用哪种格式吗? - Pravesh
2
这个答案没有被正确定义。你必须展示完整的实现方式,以便在应用到Android App中时能够完美运行。 - Zia Ur Rahman
在位图图像的情况下,我们如何使用这个泛洪填充算法? - Umair

4

以下是使用Python和OpenCV制作的快速应用程序(如果您足够努力,应该可以在Android上使用):

"""Flood fills with random color on click.  Press `q' to exit."""
import cv
import sys
import random

TOL = 10
TOL_BGR = (TOL, TOL, TOL, 0)

def click(event,x,y,flags,im):
    if event == cv.CV_EVENT_LBUTTONDOWN:
        b,g,r = [ random.random() * 255 for i in range(3) ]
        cv.FloodFill(im, (x,y), (b,g,r,0), TOL_BGR, TOL_BGR)

im = cv.LoadImage(sys.argv[1], cv.CV_LOAD_IMAGE_COLOR)
cv.NamedWindow(__file__, 1)
cv.SetMouseCallback(__file__, click, im)
while True:
    cv.ShowImage(__file__, im)
    key = cv.WaitKey(33)
    if chr(key & 0xff) == 'q':
        break
cv.SaveImage('floodfill.png', im)

每次用户点击图像时,应用程序都会使用点击位置作为种子进行泛洪填充。颜色是随机选择的。您可以通过修改TOL(或TOL_BGR)的值来更改容差。这是几次点击后的结果: enter image description here 无论您使用什么技术,通用算法都是相同的。

请问您能否发送源代码,因为我无法理解这部分内容。 - dineshprasanna
不,我不会给你发送代码。源代码已经在我的回答中了。如果您不理解任何内容,请阅读相关函数的文档--它们很容易获取。 - mpenkov
如果我使用SVG而不是普通图像,应该采取什么方法? - isuru

0

1) 将每个颜色部分拆分为单独的图像,大小与实际图像相同,其他部分为透明。 2) 在drawable文件夹中有完整的图像,每个部分都用不同的颜色绘制-这只是参考图像。

3) 将所有拆分的图像添加到帧布局中,并最初将所有拆分设置为不可见,仅将实际图像设置为可见

4) 从您的参考图像(步骤2)中为每个拆分的代码热编码颜色,例如handSplitImageColor = green;

5) 为帧布局设置侦听器,找出x和y位置,并将x和y位置传递给您的参考图像(步骤2),找出该特定位置的颜色,并将颜色与步骤4匹配,填充该图像中的特定部分并将可见性设置为true。因此,只有该部分会被颜色填充,因为其他部分是透明的。

这些是我用于解决同类型问题的步骤。

但我认为这不是更好的解决方案,但它对我很有效。


0
经过大量搜索,我得出了以下结论。它快速高效。
private void myFloodFillMethod(Point node,int targetColor, int fillColor) {
    if (targetColor != fillColor) {
        Queue<Point> queue = new LinkedList<>();
        do {
            int x = node.x;
            int y = node.y;

            while (x > 0 && getPixelColorFromArr(x - 1, y) == targetColor) {
                x--;                }
            boolean spanUp = false;
            boolean spanDown = false;

            while (x < width && checkEquality(getPixelColorFromArr(x, y),targetColor)) {
                setPixelColorFromArr(x, y, fillColor);
                if (!spanUp && y > 0
                        && checkEquality(getPixelColorFromArr(x, y - 1),targetColor)) {
                    queue.add(new Point(x, y - 1));
                    spanUp = true;
                } else if (spanUp && y > 0
                        && !checkEquality(getPixelColorFromArr(x, y - 1),targetColor)) {
                    spanUp = false;
                }
                if (!spanDown && y < height - 1
                        && checkEquality(getPixelColorFromArr(x, y + 1), targetColor)) {
                    queue.add(new Point(x, y + 1));
                    spanDown = true;
                } else if (spanDown && y < height - 1
                        && !checkEquality(getPixelColorFromArr(x, y + 1),targetColor)) {
                    spanDown = false;
                }
                x++;
            }

        } while ((node = queue.poll()) != null);
    }

}

private boolean checkEquality(int pixelColorFromArr, int targetColor) {
    return pixelColorFromArr == targetColor;
}

void fillColorInImage(Bitmap image, Point node, int targetColor, int replacementColor){

    if(targetColor ==  replacementColor) return;

    width = image.getWidth();
    height = image.getHeight();

    pixelArr = new int[width*height];

    image.getPixels(pixelArr,0,width,0,0,width,height);
    myFloodFillMethod(node,targetColor,replacementColor);

    image.setPixels(pixelArr,0,width,0,0,width,height);

}

如何调用:

fillColorInImage(bmp, point, targetColor, replacementColor);

在编程中,

bmp 是图像的位图(从图像视图中提取)

point 是用户点击的点 Point(x,y):从 event.getX()event.getY() 获取

targetColor 是该点的颜色:从 bitmap.getPixel() 获取

replacementColor 是您想要替换的颜色


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接