Javafx图片到低多边形艺术转换器

时间:2018-06-26 08:06:52

标签: image-processing javafx

我正在尝试使用javafx制作一个程序,该程序将转换这样的图片: left: normal picture, right : low poly picture

在这张照片中,背景并不是我想要的那样,但是中间的鳄梨是我想要实现的一个很好的例子。我现在拥有的是两个滤镜,它们可以根据亮度在图片中找到边缘,如下所示:

public void processImage() {
    ww = (int) Math.ceil(image.getWidth());
    hh = (int) Math.ceil(image.getHeight());
    pixelAmount = (long) ww * (long) hh;
    pxDA = new pxInfo[ww][hh];
    PixelReader pr = image.getPixelReader();
    if(pr != null) {
        System.out.println("pixel reader found");
        WritableImage i = new WritableImage(ww, hh);
        for(int x = 0; x < ww; x++) {
            for(int y = 0; y < hh; y++) {
                Color c = pr.getColor(x, y);
                double a = c.getOpacity();
                double r = c.getRed();
                double g = c.getBlue();
                double b = c.getBlue();

                double[][] gray = new double[3][3];
                for (int j = 0; j < 3; j++) {
                    for (int k = 0; k < 3; k++) {
                        if(!((j == 0 && x == 0) || (k == 0 && y == 0) || (j 
== 2 && x == ww - 1) || (k == 2 && y == hh - 1))) {
                            Color cl = pr.getColor(x - 1 + j, y - 1 + k);
                            gray[j][k] = 0.299 * cl.getRed() +  0.587 * 
cl.getGreen() + 0.114 * cl.getBlue();
                        }
                    }
                }

                // apply filter
                double gray1 = 0, gray2 = 0;
                for (int j = 0; j < 3; j++) {
                    for (int k = 0; k < 3; k++) {
                        gray1 += gray[j][k] * filter1[j][k];
                        gray2 += gray[j][k] * filter2[j][k];
                    }
                }
                double magnitude = clamp(0.0, 1.0 - Math.sqrt(gray1 * gray1 + 
gray2 * gray2), 1.0);
                Color color = new Color(magnitude, magnitude, magnitude, 1);
                i.getPixelWriter().setColor(x, y, color);
            }
        }
        stackPane.getChildren().add(new ImageView(i));
    }
}

这部分代码可以很好地工作,这些是一些结果:

在过滤器之前: before applying filters 过滤后: after applying filters 但是问题是我不知道从这里到哪里。我正在互联网上寻找各种算法,但是我真的找不到任何有明确解释的东西,所以我想在这里问。因此,如果您知道可以应用某些算法/过滤器来改进此效果,我想听听。

然后还有我实际需要创建三角/多边形的部分。假设我已应用所有过滤器,等等,我该怎么办?就像我如何将形状与灰度图片区分开?任何帮助将不胜感激。

预先感谢

Lenardjee

1 个答案:

答案 0 :(得分:3)

我对JavaFX特别不熟悉,但是我尝试使用 Python OpenCV 来解决一个非常类似的问题:

https://github.com/tasercake/lowpolypy

这就是我要做的。


常规流程:

  1. 预处理图像(双边/高斯模糊以去除噪声等)
  2. 从图像中获取关键点(使用下面详述的方法)
  3. 从关键点获取多边形(使用Delaunay三角剖分或类似算法)
  4. 阴影多边形(例如,使用多边形内所有像素的平均颜色)
  5. 后期处理(对比度,饱和度调整等)

1。预处理

在继续进行关键点提取之前,对图像进行预处理有助于去除许多不必要的高频细节。

您可以使用诸如双边过滤器高斯过滤器之类的过滤器来实现此目的。

您可能还希望在此处缩小图像以加快处理速度,但这并不是绝对必要的。


2。关键点提取

这可能是最困难的部分,也是最需要微调/实验的部分。

您可以尝试的一些方法是:

Canny Edge Detection

任何值得使用的图像处理/计算机视觉库(例如OpenCV)都应内置此功能。

此方法为您提供一个布尔图像,其中潜在边缘标记为“真”。然后,您可以选择这些点的随机子集,并将它们转换为(X,Y)坐标(或最适合您的格式)。

我发现这种方法与少量的随机化相结合,需要最少的调整。

Laplacian of Gaussian

这是另一种检测图像中显着特征的方法,但是它基于图像像素的二阶导数(与基于一阶导数的Canny滤镜相反)。

此过滤器返回一张图像,您可以对其进行标准化并将其用作权重蒙版,以从中随机采样一组关键点(也许有比这更好的使用过滤器的方法,但是我不为所动)。

随机替换

一旦您通过其他所有方法积累了一组关键点,则可以选择用一组随机生成的关键点替换所有点的一小部分随机子集。

我发现这有助于在最终输出中引入一些美观的不规则性。

摇动关键点

除了直接替换一小部分关键点外,我还对每个关键点“微动”(随机翻译)非常少量。这有助于引入更多的随机性,并允许您多次运行程序以获得一个可能良好的输出。

  

注意:请不要忘记将图像的4个角添加为关键点,否则最终将在输出周围出现空白区域。


3。将关键点连接到多边形

Delaunay Triangulation是一种算法,该算法以使这样形成的每个三角形中的最小角度最大化的方式连接平面中的一组点。 (很明显,如果您不仅仅想要三角形,这是行不通的。)


4。阴影多边形

对于每个多边形,您需要获取多边形所包围的区域内所有图像像素的平均值。 OpenCV具有(cv2.mean(image, mask))函数,通过将多边形作为二进制掩码传递,您可以在很少的行中完成此操作。


一些结果:

fox | fox_lowpoly

eminem | eminem_lowpoly