首页 文章

从Image中删除背景并仅拍摄图像部分以便在iOS中保存

提问于
浏览
8

这是我需要实现的:

  • 从相机或图库中拍摄图像

  • 从图像中删除背景并保存

  • 背景应为黑色或白色

  • 还需要删除背景阴影

Result Example:

Original Image

enter image description here

Result Image

enter image description here

This is what i have tried:

CGFloat colorMasking[6]={222,255,222,255,222,255};
CGImageRef imageRef = CGImageCreateWithMaskingColors([IMG CGImage], colorMasking);
UIImage  *resultThumbImage = [UIImage imageWithCGImage:imageRef scale:ThumbImage.scale orientation:IMG.imageOrientation];

它唯一的工作在白色背景 . 它不是更有效 . 我需要达到我在上面的图像中放置的确切结果 .

我还提到了一些参考文献:

iOS how to mask the image background color

How to remove the background of image in iphone app?

Changing the background color of a captured image from camera to white

有人可以帮我实现这个目标吗?

任何参考或将受到高度赞赏 .

提前致谢 .

2 回答

  • 7

    通常,根据经验,背景颜色与所有其他颜色的差异越大,将图像分割为前景和背景就越容易 . 在这种情况下,正如@Chris已经建议的那样,可以使用简单的色度键实现 . 下面是我在Wikipedia上描述的键控的快速实现(它用C编写,但将其转换为Objective-C应该很简单):

    /**
     * @brief Separate foreground from background using simple chroma keying.
     *
     * @param imageBGR   Image with monochrome background
     * @param chromaBGR  Color of the background (using channel order BGR and range [0, 255])
     * @param tInner     Inner threshold, color distances below this value will be counted as foreground
     * @param tOuter     Outer threshold, color distances above this value will be counted as background
     *
     * @return  Mask (0 - background, 255 - foreground, [1, 255] - partially fore- and background)
     *
     * Details can be found on [Wikipedia][1].
     *
     * [1]: https://en.wikipedia.org/wiki/Chroma_key#Programming
     */
    cv::Mat1b chromaKey( const cv::Mat3b & imageBGR, cv::Scalar chromaBGR, double tInner, double tOuter )
    {
        // Basic outline:
        //
        // 1. Convert the image to YCrCb.
        // 2. Measure Euclidean distances of color in YCrBr to chroma value.
        // 3. Categorize pixels:
        //   * color distances below inner threshold count as foreground; mask value = 0
        //   * color distances above outer threshold count as background; mask value = 255
        //   * color distances between inner and outer threshold a linearly interpolated; mask value = [0, 255]
    
        assert( tInner <= tOuter );
    
        // Convert to YCrCb.
        assert( ! imageBGR.empty() );
        cv::Size imageSize = imageBGR.size();
        cv::Mat3b imageYCrCb;
        cv::cvtColor( imageBGR, imageYCrCb, cv::COLOR_BGR2YCrCb );
        cv::Scalar chromaYCrCb = bgr2ycrcb( chromaBGR ); // Convert a single BGR value to YCrCb.
    
        // Build the mask.
        cv::Mat1b mask = cv::Mat1b::zeros( imageSize );
        const cv::Vec3d key( chromaYCrCb[ 0 ], chromaYCrCb[ 1 ], chromaYCrCb[ 2 ] );
    
        for ( int y = 0; y < imageSize.height; ++y )
        {
            for ( int x = 0; x < imageSize.width; ++x )
            {
                const cv::Vec3d color( imageYCrCb( y, x )[ 0 ], imageYCrCb( y, x )[ 1 ], imageYCrCb( y, x )[ 2 ] );
                double distance = cv::norm( key - color );
    
                if ( distance < tInner )
                {
                    // Current pixel is fully part of the background.
                    mask( y, x ) = 0;
                }
                else if ( distance > tOuter )
                {
                    // Current pixel is fully part of the foreground.
                    mask( y, x ) = 255;
                }
                else
                {
                    // Current pixel is partially part both, fore- and background; interpolate linearly.
                    // Compute the interpolation factor and clip its value to the range [0, 255].
                    double d1 = distance - tInner;
                    double d2 = tOuter   - tInner;
                    uint8_t alpha = static_cast< uint8_t >( 255. * ( d1 / d2 ) );
    
                    mask( y, x ) = alpha;
                }
            }
        }
    
        return mask;
    }
    

    可以在Github Gist中找到完整的代码示例 .

    不幸的是,你的例子不遵循这个经验法则 . 由于前景和背景的强度不同,因此很难(甚至不可能)找到一组全局参数以实现良好的分离:

    • 对象周围有黑线但对象内没有孔( tInner=50tOuter=90
      mask 1

    background substitution 1

    • 对象周围没有黑线,但对象内部没有空洞( tInner=100 ,_ tOuter=170
      mask 2

    background substitution 2

    因此,如果您无法更改图像的背景,则需要采用更复杂的方法 . 但是,快速简单的示例实现有点超出范围,但您可能希望查看image segmentationalpha matting的相关区域 .

  • 4

    我认为你需要使用一个抠像 - 虽然你选择黑色我认为它应该工作 .

    一个快速谷歌想出了this

相关问题