I am making an attempt to attract the define of a picture utilizing BezierPath based mostly on the transparency of every pixel.
Nevertheless, I am having a problem with the logic; my logic additionally attracts the inner outlines.
I solely need to draw the exterior define with BezierPath.
What’s I get (the primary form it is the unique picture, the second is the bezierPath
):
My code:
func processImage(_ picture: UIImage) -> UIBezierPath? {
guard let cgImage = picture.cgImage else {
print("Error: Could not get CGImage from UIImage")
return nil
}
let width = cgImage.width
let top = cgImage.top
// Create a context to carry out picture processing
let colorSpace = CGColorSpaceCreateDeviceGray()
let context = CGContext(information: nil, width: width, top: top, bitsPerComponent: 8, bytesPerRow: width, area: colorSpace, bitmapInfo: CGImageAlphaInfo.none.rawValue)
guard let context = context else {
print("Error: Could not create CGContext")
return nil
}
// Draw the picture into the context
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, top: top))
// Carry out Canny edge detection
guard let edgeImage = context.makeImage() else {
print("Error: Could not create edge picture")
return nil
}
// Create a bezier path for the define of the form
let bezierPath = UIBezierPath()
// Iterate over the picture pixels to seek out the perimeters
for y in 0..<top {
for x in 0..<width {
let pixel = edgeImage.pixel(x: x, y: y)
if pixel > 0 {
let leftPixel = (x > 0) ? edgeImage.pixel(x: x - 1, y: y) : 0
let rightPixel = (x < width - 1) ? edgeImage.pixel(x: x + 1, y: y) : 0
let abovePixel = (y > 0) ? edgeImage.pixel(x: x, y: y - 1) : 0
let belowPixel = (y < top - 1) ? edgeImage.pixel(x: x, y: y + 1) : 0
if leftPixel == 0 || rightPixel == 0 || abovePixel == 0 || belowPixel == 0 {
bezierPath.transfer(to: CGPoint(x: CGFloat(x), y: CGFloat(y)))
bezierPath.addLine(to: CGPoint(x: CGFloat(x) + 1.0, y: CGFloat(y) + 1.0))
}
}
}
}
return bezierPath
}
extension CGImage {
func pixel(x: Int, y: Int) -> UInt8 {
let information = self.dataProvider!.information
let pointer = CFDataGetBytePtr(information)
let bytesPerRow = self.bytesPerRow
let pixelInfo = (bytesPerRow * y) + x
return pointer![pixelInfo]
}
}