【问题标题】:Trim UIImage border修剪 UIImage 边框
【发布时间】:2013-11-18 20:10:13
【问题描述】:

这是我要修剪的图像示例。我想去掉图像周围的边框(在这种情况下是顶部和底部的黑条)。

我在 Github 上找到了一个库:CKImageAdditions,但它似乎不起作用。当我传入 UIColor(带有 RGB 颜色)时,它只会返回相同的图像。

我可以找到很多示例和类别类,它们可以修剪带有任何透明像素作为边框的 UIImage,但在这种情况下,我需要修剪黑色。我已经对图像中的颜色进行了采样,它们的颜色值确实是 255,但它似乎与上述库正在寻找的不匹配。

是否有人有他们使用过的库或任何见解?我已经搜索和搜索,CKImageAdditions 是我能找到的唯一一个广告用颜色修剪的东西(尽管不幸的是在我的情况下不起作用)。

【问题讨论】:

  • 您知道新修剪的图像的尺寸,还是应该是动态的并尝试您指定的任何颜色?
  • @PeterFoti 我不在乎尺寸。我把它放在 UIImageView 中,UIViewContentModeScaleAspectFill 作为UIContentMode。而且我只想修剪黑色边框,我不在乎其他颜色。谢谢。
  • 但是这些边框是烘焙到图像中的,还是在您将其添加到视图后添加的?
  • @PeterFoti 这就是给我图像的方式,所以边框就在那里,我想在将它们显示在UIImageView 之前将它们去掉
  • 您可以通过逐像素(逐行)扫描图像并在像素行平均颜色不是黑色时搜索来手动完成。如果你找到它 - 停止你的算法,因为你找到了第一个边界。对图像的每一侧重复此算法(对于左侧和右侧,您应该逐列迭代像素,而不是顶部和底部的行)。您可以使用此答案中的像素扫描方法:stackoverflow.com/questions/2342327/…

标签: ios objective-c c uiimage cgimage


【解决方案1】:

我最终从 function in CKImageAdditions 自定义了一个方法,据说它具有此功能,但我无法让它工作。它只是不会修剪颜色,所以我改为检查像素的 RGB 值是否为\0(黑色)。不幸的是,CKImageAdditions 找不到黑色像素。

由于我想要修剪的图像有时没有超级黑条(有时它们会有一个带有较浅深色的杂散像素或其他东西)我在该方法中添加了GPUImage 功能,它基本上只是创建了一个黑白版本的图像,上面有一个强大的过滤器,所以任何深色变成黑色,任何浅色变成白色,使黑条边框更加突出,并在我在方法中寻找它们时确保更好的结果。当然,最后我会根据黑白图像的结果裁剪原始图像。

这是我的代码:

typedef struct Pixel { uint8_t r, g, b, a; } Pixel;

+(UIImage*)trimBlack:(UIImage*)originalImage {
    GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:originalImage];
    GPUImageLuminanceThresholdFilter *stillImageFilter = [[GPUImageLuminanceThresholdFilter alloc] init];
    stillImageFilter.threshold = 0.1;
    [stillImageSource addTarget:stillImageFilter];
    [stillImageSource processImage];
    UIImage *imageToProcess = [stillImageFilter imageFromCurrentlyProcessedOutput];

    RMImageTrimmingSides sides = RMImageTrimmingSidesAll;
    CGImageRef image = imageToProcess.CGImage;
    void * bitmapData = NULL;
    CGContextRef context = CKBitmapContextAndDataCreateWithImage(image, &bitmapData);

    Pixel *data = bitmapData;

    size_t width = CGBitmapContextGetWidth(context);
    size_t height = CGBitmapContextGetHeight(context);

    size_t top = 0;
    size_t bottom = height;
    size_t left = 0;
    size_t right = width;

    // Scan the left
    if (sides & RMImageTrimmingSidesLeft) {
        for (size_t x = 0; x < width; x++) {
            for (size_t y = 0; y < height; y++) {
                Pixel pixel = data[y * width + x];
                if (pixel.r != '\0' && pixel.g != '\0' && pixel.b != '\0') {
                    left = x;
                    goto SCAN_TOP;
                }
            }
        }
    }

    // Scan the top
SCAN_TOP:
    if (sides & RMImageTrimmingSidesTop) {
        for (size_t y = 0; y < height; y++) {
            for (size_t x = 0; x < width; x++) {
                Pixel pixel = data[y * width + x];
                if (pixel.r != '\0' && pixel.g != '\0' && pixel.b != '\0') {
                    top = y;
                    goto SCAN_RIGHT;
                }
            }
        }
    }

    // Scan the right
SCAN_RIGHT:
    if (sides & RMImageTrimmingSidesRight) {
        for (size_t x = width-1; x >= left; x--) {
            for (size_t y = 0; y < height; y++) {
                Pixel pixel = data[y * width + x];
                if (pixel.r != '\0' && pixel.g != '\0' && pixel.b != '\0') {
                    right = x;
                    goto SCAN_BOTTOM;
                }
            }
        }
    }

    // Scan the bottom
SCAN_BOTTOM:
    if (sides & RMImageTrimmingSidesBottom) {
        for (size_t y = height-1; y >= top; y--) {
            for (size_t x = 0; x < width; x++) {
                Pixel pixel = data[y * width + x];
                if (pixel.r != '\0' && pixel.g != '\0' && pixel.b != '\0') {
                    bottom = y;
                    goto FINISH;
                }
            }
        }
    }

FINISH:
    CGContextRelease(context);
    free(bitmapData);

    CGRect rect = CGRectMake(left, top, right - left, bottom - top);
    return [originalImage imageCroppedToRect:rect];
}

感谢以上代码中使用的库的开发人员的辛勤工作,当然所有功劳都归功于他们!

【讨论】:

  • 嘿,如果有人稍后阅读此内容:如果您想从图像中修剪白色边框,这将不起作用。即使您将所有 '\0' 更改为 '\255'。 (另外,要尝试此代码,您需要 CKImageAdditions & UIImage+FX)
【解决方案2】:

现在我调整了您的解决方案,因为 GPUImage 的 imageFromCurrentlyProcessedOutput 方法已被删除并替换为另一种根本不起作用的方法。

还调整了图像的裁剪方式并删除了一些刚刚损坏的内容。似乎有效。

typedef struct Pixel { uint8_t r, g, b, a; } Pixel;

-(UIImage*)trimBlack:(UIImage*)originalImage {
    GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:originalImage];
    GPUImageLuminanceThresholdFilter *stillImageFilter = [[GPUImageLuminanceThresholdFilter alloc] init];
    stillImageFilter.threshold = 0.1;
    [stillImageSource addTarget:stillImageFilter];
    [stillImageSource processImage];
    [stillImageSource useNextFrameForImageCapture];
    
    //UIImage *imageToProcess = [stillImageFilter imageFromCurrentFramebufferWithOrientation:UIImageOrientationUp];
    //UIImage *imageToProcess = [UIImage imageWithCGImage:[stillImageFilter newCGImageFromCurrentlyProcessedOutput]];
    UIImage *imageToProcess = originalImage;
    
    //RMImageTrimmingSides sides = RMImageTrimmingSidesAll;
    CGImageRef image = imageToProcess.CGImage;
    void * bitmapData = NULL;
    CGContextRef context = CKBitmapContextAndDataCreateWithImage(image, &bitmapData);
    
    Pixel *data = bitmapData;
    
    size_t width = CGBitmapContextGetWidth(context);
    size_t height = CGBitmapContextGetHeight(context);
    
    size_t top = 0;
    size_t bottom = height;
    size_t left = 0;
    size_t right = width;
    
    // Scan the left
    //if (sides & RMImageTrimmingSidesLeft) {
        for (size_t x = 0; x < width; x++) {
            for (size_t y = 0; y < height; y++) {
                Pixel pixel = data[y * width + x];
                if (pixel.r != '\0' && pixel.g != '\0' && pixel.b != '\0') {
                    left = x;
                    goto SCAN_TOP;
                }
            }
        }
    //}
    
    // Scan the top
SCAN_TOP:
    //if (sides & RMImageTrimmingSidesTop) {
        for (size_t y = 0; y < height; y++) {
            for (size_t x = 0; x < width; x++) {
                Pixel pixel = data[y * width + x];
                if (pixel.r != '\0' && pixel.g != '\0' && pixel.b != '\0') {
                    top = y;
                    goto SCAN_RIGHT;
                }
            }
        }
    //}
    
    // Scan the right
SCAN_RIGHT:
    //if (sides & RMImageTrimmingSidesRight) {
        for (size_t x = width-1; x >= left; x--) {
            for (size_t y = 0; y < height; y++) {
                Pixel pixel = data[y * width + x];
                if (pixel.r != '\0' && pixel.g != '\0' && pixel.b != '\0') {
                    right = x;
                    goto SCAN_BOTTOM;
                }
            }
        }
    //}
    
    // Scan the bottom
SCAN_BOTTOM:
    //if (sides & RMImageTrimmingSidesBottom) {
        for (size_t y = height-1; y >= top; y--) {
            for (size_t x = 0; x < width; x++) {
                Pixel pixel = data[y * width + x];
                if (pixel.r != '\0' && pixel.g != '\0' && pixel.b != '\0') {
                    bottom = y;
                    goto FINISH;
                }
            }
        }
    //}
    
FINISH:
    CGContextRelease(context);
    free(bitmapData);
    
    CGRect rect = CGRectMake(left, top, right - left, bottom - top);
    CGImageRef imageRef = CGImageCreateWithImageInRect([originalImage CGImage], rect);
    UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    return croppedImage;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-07
    • 2016-10-25
    • 2013-07-27
    • 2011-08-04
    • 1970-01-01
    • 2011-04-17
    • 2021-08-15
    • 1970-01-01
    相关资源
    最近更新 更多