Reputation: 19
I have a transparent image with an object in it, and I would like to add a border around the object (i.e., the edge of the object) in SwiftUI. The object is the only thing visible in the image, and I don't want to modify the image itself.
I want to achieve this by overlaying a path that follows the edge of the object, creating the appearance of a border around it, using SwiftUI's Canvas and Vision framework for detecting the object's edges.
Requirements: The image must remain unchanged. The border should be drawn around the object (not the entire image) using the detected edges. I want to use ZStack to layer the image and the path, so it looks like a border around the object. What I've tried: I've been using Vision's VNDetectContoursRequest to detect contours, but it seems to return a path for the whole image (bounding box), not just the object. I've attempted to overlay the path on the image using ZStack, but it doesn't give the desired result of just drawing the border around the object.
import SwiftUI
import Vision
struct ObjectOutlineView: View {
let imageName: String
var body: some View {
GeometryReader { geometry in
ZStack {
// Original Image
Image(uiImage: UIImage(named: imageName)!)
.resizable()
.scaledToFit()
.frame(width: geometry.size.width, height: geometry.size.height)
// Custom path around object
if let path = createOutlinePath(for: imageName, in: geometry.size) {
path
.stroke(Color.blue, lineWidth: 5) // Border color and width
}
}
}
}
// This function generates the path using Vision contours
func createOutlinePath(for imageName: String, in size: CGSize) -> Path? {
guard let uiImage = UIImage(named: imageName),
let cgImage = uiImage.cgImage else { return nil }
var outlinePath = Path()
// Perform Vision request to detect contours
let request = VNDetectContoursRequest()
request.contrastAdjustment = 1.0
request.detectsDarkOnLight = true
request.revision = VNDetectContoursRequestRevision2
let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
do {
try handler.perform([request])
// Extract outermost contour
guard let observation = request.results?.first as? VNContoursObservation else { return nil }
// Get the outer contour
let outerContour = try observation.contour(at: 0)
// Convert the contour to a path
var isFirstPoint = true
for i in 0..<outerContour.pointCount {
let normalizedPoint = outerContour.normalizedPoints[i]
let x = CGFloat(normalizedPoint.x) * size.width
let y = CGFloat(1 - normalizedPoint.y) * size.height // Flip Y-axis for SwiftUI
if isFirstPoint {
outlinePath.move(to: CGPoint(x: x, y: y))
isFirstPoint = false
} else {
outlinePath.addLine(to: CGPoint(x: x, y: y))
}
}
outlinePath.closeSubpath()
} catch {
print("Error performing contour detection: \(error.localizedDescription)")
return nil
}
return outlinePath
}
}
struct ContentView: View {
var body: some View {
ObjectOutlineView(imageName: "your_image_name") // Replace with your image name
.frame(width: 300, height: 300)
}
}
What am I looking for? I want to ensure that only the border of the object inside the image is drawn. The path should not affect or modify the original image. Any solution using ZStack and Vision or any alternative approach would be appreciated! Details: The image is transparent, with just the object visible. I am using SwiftUI to display the image and path.
How can I properly overlay a path around the object without changing the image itself?
I attached image that what I want in result
Upvotes: 0
Views: 32