如何从位图区域获取多边形形状

How do I get a polygon shape from a bitmap area

所以 - 这是我问 "how do I" 问题的罕见情况之一,我实际上什么也没尝试,因为我不知道从哪里开始。

这是我的问题。

我有一张照片,我在绿色屏幕上进行了键控,然后变成了一个遮罩,其中有一些像素是透明的,其余的是黑色的。假设这个黑色的形状是照片主体的上胸部和头部。

我知道如何找到所有的黑色像素,我可以很容易地找出透明像素旁边的黑色像素,这样我就可以很容易地画出黑色形状的轮廓,但这就是我 运行想法...如何将该轮廓转换为可用作多边形的连续点数组?

Finished my analysis, I've created an S.V.G. vector path from a mask bitmap. This gives you an optimised sequence path of all the points in the contour frame.

The process of converting a vector outline to a bitmap is called rendering. The converse process of turning bitmaps into outlines is called tracing.

适用的其他标签:遮罩、矢量图形、矢量化、矢量、追踪、贝塞尔曲线、贝塞尔曲线...

链接:
THEORY PDF Potrace: a polygon-based tracing algorithm
Potrace wiki
Potrace Android port and frontend
第一点很简单,用 alpha 替换绿屏(色键)。我将创建一个掩码,以解析为向量 SVG
到目前为止我有什么:
图像 1 是原始图像(绿屏)[chromo-key]。 图片 2 绿屏替换为 Alpha 蒙版。
Image 3 Contour Frame (as a bitmap with Alpha) Image 4 Mask.

图片 5 这是轮廓作为 SVG 矢量文件(将以下文本保存到 svg.svg 文件并在浏览器中加载它以验证它;O)[它看起来像图 3]).

<svg width="320" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg" desc="Created by Jon Goodwin maskActivity version 1.1.2" >
<path desc="l 0 p 0" fill="rgb(255,255,255)" stroke="rgb(0,0,0)" stroke-width="1" opacity="1.0"
d="M 125.5 13.0 L 136.0 13.5 L 145.5 15.0 L 157.5 18.0 L 166.5 23.0 L 176.5 30.0 Q 184.4 32.1 188.0 38.5 L 196.0 50.5 Q 194.8 56.3 198.0 57.5 
L 201.5 65.0 L 205.0 73.5 L 207.0 77.5 L 207.0 84.5 L 206.5 86.0 L 210.0 88.5 L 209.0 91.5 L 215.0 93.5 Q 219.7 98.3 219.0 108.5 L 218.0 111.5 
L 218.0 120.5 L 217.0 127.5 L 216.0 129.5 Q 216.5 134.5 212.5 135.0 L 208.0 136.5 L 208.0 149.5 Q 206.8 154.3 209.0 155.5 L 210.5 162.0 
L 214.5 163.0 L 218.0 165.5 Q 219.8 168.8 224.5 169.0 L 238.5 176.0 L 250.5 184.0 L 266.5 193.0 L 278.5 200.0 L 283.5 203.0 L 295.0 212.5 
L 295.5 214.0 L 299.0 216.5 L 306.0 226.5 L 308.5 231.0 L 312.0 239.5 L 66.5 240.0 L 66.0 237.5 L 68.0 234.5 
L 69.0 227.5 Q 72.6 226.1 72.5 221.0 L 78.0 214.5 L 91.5 199.0 L 96.5 198.0 L 102.0 195.5 L 104.5 192.0 L 106.0 191.5 L 103.0 185.5 
L 101.0 180.5 Q 102.0 172.5 97.5 170.0 L 94.0 167.5 L 84.5 132.0 L 84.0 124.5 Q 84.8 120.8 82.5 120.0 Q 80.3 119.3 81.0 115.5 L 82.0 112.5 
L 81.0 109.5 L 81.0 102.5 L 82.0 99.5 L 82.0 93.5 L 81.0 89.5 L 83.0 84.5 L 81.5 85.0 Q 77.5 85.5 77.0 82.5 L 78.0 70.5 Q 77.1 62.1 80.0 57.5 
Q 77.3 56.8 78.0 52.5 Q 79.6 45.5 84.5 42.0 L 86.0 41.5 Q 85.3 37.8 87.5 37.0 L 93.5 31.0 L 95.0 30.5 L 101.5 19.0 Q 106.3 20.3 107.5 18.0 
L 111.5 17.0 L 125.5 13.0 Z" />
</svg>


关于 SVG 的注释: SVG 中的路径具有紧凑的编码。 例如 M(对于 'move to')在初始数字 x 和 y 坐标之前,并且 L(线到)在应该画线的点之前。 更多命令字母(C、S、Q、T 和 A) 在用于绘制各种贝塞尔曲线和椭圆曲线的数据之前。 Q 是二次贝塞尔曲线, Z 用于关闭路径。在所有情况下, 绝对坐标遵循大写字母命令和 在等效的小写字母后使用相对坐标。

轮廓框架 是一个棘手的位(我发现了一些编码魔法)。它是一个位图,图像的所有白色部分都是一个 alpha。事实上,在连续的线轮廓框架中有一些颜色(即o.k。)。
(我们 [I], ;O|) 可能 approaching 现在问题的 nub ;O) )
你说:

I can easily draw an outline of the black shape but that's where I run out of ideas... how do I transform that outline into a sequential array of points that can be used as a polygon?

嗯,Tricky(取决于你想要什么多边形,我想 SVG 矢量图形会给我们掩码位图中的点序列),但它是一个封闭的连续循环(没有孔,一条线很粗),还不错。

没有外部库或依赖项。
这是 changeColor() 代码(图片 1图片 2):
像这样调用:

Bitmap chromoBmp       = changeColor(origBmp, 0xff00FF00, 0x00000000, false, "chromo");//green to alpha


private Bitmap changeColor(Bitmap src, int colorToReplace, int colorThatWillReplace, boolean not, String log) {
    int width = src.getWidth();
    int height = src.getHeight();
int[] pixels = new int[width * height];
// get pixel array from source
    src.getPixels(pixels, 0, width, 0, 0, width, height);

Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
int pixel;

 // iteration through pixels
for (int y = 0; y < height; ++y) {
    for (int x = 0; x < width; ++x) {
        // get current index in 2D-matrix
        int index = y * width + x;
        pixel = pixels[index];

        if(not == true)
        {
            if(pixel != colorToReplace)
            {
                pixels[index] = colorThatWillReplace;
            }
        }
        else
        {
            if(pixel == colorToReplace)
            {
                pixels[index] = colorThatWillReplace;
            }
        }
    }//x
}//y

bmOut.setPixels(pixels, 0, width, 0, 0, width, height);
return bmOut;
}

还有一些相当重要(魔法)processingBitmap_BlurContour()Image2 to Image3):
像这样调用:

Bitmap framContourBmp  = processingBitmap_BlurContour(changedBmp, 1);//thickness of frame


private Bitmap processingBitmap_BlurContour(Bitmap src, int blurValue){
    int width = src.getWidth();
    int height = src.getHeight();

BlurMaskFilter blurMaskFilter;
Paint paintBlur = new Paint();

Bitmap dest = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);//***VERY IMPORTANT Bitmap.Config.RGB_565 **NOT** Bitmap.Config.ARGB_8888
Canvas canvas = new Canvas(dest);

//Create background in Black
Bitmap alpha = src.extractAlpha();
paintBlur.setColor(0xFF00FF00);//green with alpha set to FF
canvas.drawBitmap(alpha, 0, 0, paintBlur);

//Create outer blur, in Black
blurMaskFilter = new BlurMaskFilter(blurValue, BlurMaskFilter.Blur.OUTER);
paintBlur.setMaskFilter(blurMaskFilter);
canvas.drawBitmap(alpha, 0, 0, paintBlur);

//Create inner blur
blurMaskFilter = new BlurMaskFilter(blurValue, BlurMaskFilter.Blur.INNER);
paintBlur.setMaskFilter(blurMaskFilter);
canvas.drawBitmap(src, 0, 0, paintBlur);

return dest;
   }//processingBitmap_BlurContour

制作位图蒙版(Image2Image4):

Bitmap changedBmp = changeColor(bmp, 0,  0xff000000, true, "mask");//any col NOT trans(black) -> opaque black