应用边框到图像形状

7
在我的应用程序中,我有各种不同形状的图像,比如树、云(示例图像附在下面)。我想通过编程方式为这些形状添加边框。比如如果图像是树,则需要突出显示树形状。由于使用 calayer 会将边框应用到 UIImageView 上,所以我不能使用它。请问有人能指导我如何实现吗?

将图像绘制两次,先应用比例尺。如果图像不透明(但是是黑白的),则进行遮罩处理。 - Wain
您想要边框始终显示还是仅在选择模式下显示? - codercat
我希望边框颜色随机变化。 - Pooja M. Bohora
@Wain:谢谢你的回复。我按照你说的做了,将两张图片合并成一张带边框的图片 :) - Pooja M. Bohora
4个回答

3
这可以通过使用一系列的CIFilters来实现。查看下面步骤相应的图像。在我的示例中,基础图像是具有透明背景的彩色图像,而掩模是黑白图像。
  1. 使用CIEdges从掩模中检测边缘。
  2. 然后通过应用圆盘最大值滤波器(CIMorphologyMaximum)使边缘变粗。
  3. 使用CIMaskToAlpha将边框图像从黑白转换为透明和白色。
  4. 将原始图像覆盖在边框上。

完整代码如下:

let base = CIImage(cgImage: baseImage.cgImage!)
let mask = CIImage(cgImage: maskImage.cgImage!)
        
// 1
let edges = mask.applyingFilter("CIEdges", parameters: [
   kCIInputIntensityKey: 1.0
])
    
// 2    
let borderWidth = 0.02 * min(baseImage.size.width, baseImage.size.height)
let wideEdges = edges.applyingFilter("CIMorphologyMaximum", parameters: [
    kCIInputRadiusKey: borderWidth
])
        
// 3
let background = wideEdges.applyingFilter("CIMaskToAlpha")
      
// 4  
let composited = base.composited(over: background)
        
// Convert back to UIImage
let context = CIContext(options: nil)
let cgImageRef = context.createCGImage(composited, from: composited.extent)!
return UIImage(cgImage: cgImageRef)


如果我想应用内边框怎么办? - DanielZanchi
@DanielZanchi 我会将边框覆盖在基础图像上,然后使用蒙版去除边框的外半部分。 - nikstar
@nikstar 很棒的解决方案!如何将轮廓颜色更改为例如黑色? - hotdogsoup.nl

2

我刚刚做了同样的事情,但是加上了白色边框。我创建了一个带有白色主体和4像素黑色描边的遮罩,以便在目标图像周围获得我想要的统一边框。以下利用Core Image滤镜来遮掩纯色背景(用作边框),然后遮掩并合成目标图像。

// The two-tone mask image
UIImage *maskImage = [UIImage imageNamed: @"Mask"];

// Create a filler image of whatever color we want the border to be (in my case white)
UIGraphicsBeginImageContextWithOptions(maskImage.size, NO, maskImage.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, UIColor.whiteColor.CGColor);
CGContextFillRect(context, CGRectMake(0.f, 0.f, maskImage.size.width, maskImage.size.height));
UIImage *whiteImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// Use CoreImage to mask the colored background to the mask (the entire opaque region of the mask)
CIContext *ciContext = [CIContext contextWithOptions: nil];
CIFilter *filter = [CIFilter filterWithName: @"CIBlendWithAlphaMask"];
[filter setValue: [CIImage imageWithCGImage: whiteImage.CGImage]
          forKey: kCIInputImageKey];
[filter setValue: [CIImage imageWithCGImage: maskImage.CGImage]
          forKey: kCIInputMaskImageKey];

CIImage *whiteBackground = filter.outputImage;

// scale the target image to the size of the mask (accounting for image scale) 
// ** Uses NYXImageKit
image = [image scaleToSize: CGSizeMake(maskImage.size.width * maskImage.scale, maskImage.size.height * maskImage.scale)
                 usingMode: NYXResizeModeAspectFill];

 // finally use Core Image to create our image using the masked white from above for our border and the inner (white) area of our mask image to mask the target image before compositing
 filter = [CIFilter filterWithName: @"CIBlendWithMask"];
 [filter setValue: [CIImage imageWithCGImage: image.CGImage]
           forKey: kCIInputImageKey];
 [filter setValue: whiteBackground
           forKey: kCIInputBackgroundImageKey];
 [filter setValue: [CIImage imageWithCGImage: maskImage.CGImage]
           forKey: kCIInputMaskImageKey];

 image = [UIImage imageWithCGImage: [ciContext createCGImage: filter.outputImage
                                                    fromRect: [filter.outputImage extent]]];

几年后的现在来看可能有点牵强,但你是否有完整的代码片段,包含合成部分,并且可以在某处提供?我正在使用Swift处理类似的问题。 - Edouard Barbier
@EdouardBarbier 抱歉,我无法找到那段代码片段的来源。您还想做什么?如果我没记错的话,那个片段是完整的函数(减去声明和返回语句)。 - greg
谢谢您及时回复。我想更好地理解您是如何在遮罩上设置4像素描边,以及合成的原理(我对CoreImage非常新手)。我的最终目标是能够用可变粗细的边框轮廓PNG贴纸。 - Edouard Barbier
这是好消息和坏消息。我找到了使用它的项目。我的遮罩是一个圆形,所以我最终改变了代码,在我创建的使用 bezierPathWithRoundedRect 来定义半径为图片直径的 1/2 的贝塞尔路径中绘制图像。有一个路径可以很容易地描边以得到一致的边框。你的遮罩始终相同吗?如果是这样,将其定义为贝塞尔路径-可以使用基本形状硬编码坐标,或从 SVG 导入。路径使事情更加容易。 - greg

2
简单的方法是将图片绘制两次,第一次应用小比例来稍微放大图片。如果图像不透明但是是黑白的,则需要进行遮罩处理。

1
这很优雅,但问题在于边界不会在整个形状中保持相同。它会在靠近中心的区域变得更小。边缘检测的答案可能更有前途,但计算上更加复杂。 - Rob
@Rob:感谢您的反馈,但我的形状不是固定或相同的。它可以是树、多边形、正方形、雨伞等任何形状,因此请告诉我是否有通用解决方案,因为形状可以是任何形状。 - Pooja M. Bohora
@PoojaManiklalBohora 这就是我的观点。这就是为什么我认为这个看似简单的解决方案对你来说不起作用。 - Rob

1
你可以使用OpenCV框架将边框应用于图像中的对象。
查看此链接。在此链接中,检测了图像的边缘并应用了边框。我希望这能给出您想要的确切思路。

https://github.com/BloodAxe/OpenCV-Tutorial


谢谢,但这不是我想要的精确内容。 - Pooja M. Bohora

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接