Iphone iOS如何计算曲线包围的像素数/面积?

Iphone iOS如何计算曲线包围的像素数/面积?,iphone,objective-c,ios,area,curve,Iphone,Objective C,Ios,Area,Curve,我得到了一条任意形状的曲线,包围了一些区域我想估算曲线在iPhone/iPad屏幕上所包围的像素数。我怎么做 曲线定义为点的连续x/y坐标 曲线是闭合的 通过用户的触摸绘制曲线(touchesMoved方法),I 不知道它是什么样子 我想用颜色填充闭合曲线,然后计算屏幕截图中这种颜色的像素数。这意味着我需要知道如何以编程方式用颜色填充闭合曲线 有没有其他我没想到的方法 谢谢大家! 我会把这幅画作为CGIMage抓取 (CGBitmapContextCreateImage(UIGraphic

我得到了一条任意形状的曲线,包围了一些区域我想估算曲线在iPhone/iPad屏幕上所包围的像素数。我怎么做

  • 曲线定义为点的连续x/y坐标
  • 曲线是闭合的
  • 通过用户的触摸绘制曲线(touchesMoved方法),I 不知道它是什么样子

我想用颜色填充闭合曲线,然后计算屏幕截图中这种颜色的像素数。这意味着我需要知道如何以编程方式用颜色填充闭合曲线

有没有其他我没想到的方法


谢谢大家!

我会把这幅画作为CGIMage抓取

(CGBitmapContextCreateImage(UIGraphicsGetCurrentContext())

然后,如上所述,使用“整体填充”方法来计算像素。
(Google Flood Fill)

让我们通过创建一个包围曲线的石英路径来实现这一点。然后我们将创建一个位图上下文并在该上下文中填充路径。然后我们可以检查位图并计算填充的像素数。我们将用一个方便的函数来包装这一切:

static double areaOfCurveWithPoints(const CGPoint *points, size_t count) {
首先,我们需要创建路径:

    CGPathRef path = createClosedPathWithPoints(points, count);
然后我们需要得到路径的边界框。
CGPoint
坐标不必是整数,但位图必须具有整数维,因此我们将得到一个至少与路径边界框一样大的整数边界框:

    CGRect frame = integralFrameForPath(path);
我们还需要确定位图的宽度(以字节为单位):

    size_t bytesPerRow = bytesPerRowForWidth(frame.size.width);
    CGContextRef gc = createBitmapContextWithFrame(frame, bytesPerRow);
现在我们可以创建位图:

    size_t bytesPerRow = bytesPerRowForWidth(frame.size.width);
    CGContextRef gc = createBitmapContextWithFrame(frame, bytesPerRow);
位图创建时用黑色填充。我们将用白色填充路径:

    CGContextSetFillColorWithColor(gc, [UIColor whiteColor].CGColor);
    CGContextAddPath(gc, path);
    CGContextFillPath(gc);
现在,我们已经完成了路径,因此可以释放它:

    CGPathRelease(path);
    CGContextRelease(gc);
接下来,我们将计算填充的面积:

    double area = areaFilledInBitmapContext(gc);
现在我们已经完成了位图上下文,因此可以释放它:

    CGPathRelease(path);
    CGContextRelease(gc);
最后,我们可以返回我们计算的面积:

    return area;
}
好吧,那很简单!但是我们必须编写所有这些帮助函数。让我们从顶部开始。创建路径很简单:

static CGPathRef createClosedPathWithPoints(const CGPoint *points, size_t count) {
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddLines(path, NULL, points, count);
    CGPathCloseSubpath(path);
    return path;
}
获取路径的积分边界框也很简单:

static CGRect integralFrameForPath(CGPathRef path) {
    CGRect frame = CGPathGetBoundingBox(path);
    return CGRectIntegral(frame);
}
要选择位图每行的字节数,我们可以只使用路径边界框的宽度。但我认为Quartz喜欢使用二次幂的倍数。我还没有对此进行任何测试,因此您可能需要进行实验。现在,我们将宽度取整为64的下一个最小倍数:

static size_t bytesPerRowForWidth(CGFloat width) {
    static const size_t kFactor = 64;
    // Round up to a multiple of kFactor, which must be a power of 2.
    return ((size_t)width + (kFactor - 1)) & ~(kFactor - 1);
}
我们使用计算的大小创建位图上下文。我们还需要转换坐标系的原点。为什么?因为路径边界框的原点可能不在(0,0)

最后,我们需要编写实际计算填充像素数的帮助程序。我们必须决定如何计算像素数。每个像素由一个无符号8位整数表示。黑色像素为0。白色像素为255。中间的数字是灰色阴影。石英在使用灰色像素填充路径时会消除路径边缘的锯齿s、 因此,我们必须决定如何计算这些灰度像素

一种方法是定义一个阈值,如128。阈值上或阈值上的任何像素都计为已填充,其余像素计为未填充

另一种方法是将灰色像素计算为部分填充,并将部分填充相加。因此,两个完全半填充的像素组合起来,并计算为一个完全填充的像素。让我们这样做:

static double areaFilledInBitmapContext(gc) {
    size_t width = CGBitmapContextGetWidth(gc);
    size_t height = CGBitmapContextGetHeight(gc);
    size_t stride = CGBitmapContextGetBytesPerRow(gc);
    uint8_t *pixels = CGBitmapContextGetData(gc);
    uint64_t coverage = 0;
    for (size_t y = 0; y < height; ++y) {
        for (size_t x = 0; x < width; ++x) {
            coverage += pixels[y * stride + x];
        }
    }
    return (double)coverage / UINT8_MAX;
}
静态双区域填充位图上下文(gc){
size\u t width=CGBitmapContextGetWidth(gc);
size\u t height=CGBitmapContextGetHeight(gc);
size_t stride=CGBitmapContextGetBytesPerRow(gc);
uint8_t*像素=CGBitmapContextGetData(gc);
uint64_t覆盖率=0;
用于(尺寸y=0;y<高度;++y){
用于(尺寸x=0;x

你可以在Google“flood filling algorithm”中找到所有捆绑的代码。

Google“flood filling algorithm”。此外,你可以做的是数值积分。组成曲线的X、Y坐标是连续的吗?或者曲线是一组小向量吗?这看起来像是我作为iOS开发人员的最后一次面试中的一个问题:“在Java中实现泛洪算法”。“在Java中?我想,这是一个iOS职位的面试。为什么是Java?”“我们只希望开发人员能够完成所有工作-我需要能够检查您的答案”