Впровадження видалення фону зображення з штучним інтелектом в мобільному додатку
Видалення фону — одна з небагатьох AI-завдань, які реально працюють на пристрої без втрати якості. На iOS з Vision + Core ML, на Android з ML Kit або ONNX Runtime — результат за 100–300 мс без мережевих запитів. Хмарні API потрібні лише для граничних випадків: тонкі волосся, прозорі об'єкти, складні текстури.
На пристрої: iOS з Vision та Core ML
Apple додала видалення фону в VisionKit починаючи з iOS 16 через VNGenerateForegroundInstanceMaskRequest:
import Vision
import CoreImage.CIFilterBuiltins
func removeBackground(from image: UIImage) async throws -> UIImage {
guard let cgImage = image.cgImage else { throw BGRemovalError.invalidImage }
let request = VNGenerateForegroundInstanceMaskRequest()
let handler = VNImageRequestHandler(cgImage: cgImage)
try handler.perform([request])
guard let result = request.results?.first else { throw BGRemovalError.noResult }
// Отримуємо маску переднього плану
let maskBuffer = try result.generateScaledMaskForImage(forInstances: result.allInstances, from: handler)
// Застосовуємо маску до вихідного зображення через Core Image
let ciImage = CIImage(cgImage: cgImage)
let mask = CIImage(cvPixelBuffer: maskBuffer)
let blendFilter = CIFilter.blendWithMask()
blendFilter.inputImage = ciImage
blendFilter.maskImage = mask
blendFilter.backgroundImage = CIImage.empty() // прозорий фон
guard let outputCI = blendFilter.outputImage,
let outputCG = CIContext().createCGImage(outputCI, from: outputCI.extent) else {
throw BGRemovalError.filterFailed
}
return UIImage(cgImage: outputCG)
}
VNGenerateForegroundInstanceMaskRequest працює через нейромережу Apple, оптимізовану для Neural Engine. На iPhone 13+ — 80–150 мс на фото з камери. Без інтернету, без оплати за API.
Для iOS 15 та нижче — VNGeneratePersonSegmentationRequest (лише люди, не довільні об'єкти):
let request = VNGeneratePersonSegmentationRequest()
request.qualityLevel = .accurate // або .balanced, .fast
request.outputPixelFormat = kCVPixelFormatType_OneComponent8
На пристрої: Android з ML Kit
class BackgroundRemover(private val context: Context) {
private val segmenter = Segmentation.getClient(
SelfieSegmenterOptions.Builder()
.setDetectorMode(SelfieSegmenterOptions.SINGLE_IMAGE_MODE)
.enableRawSizeMask()
.build()
)
suspend fun removeBackground(bitmap: Bitmap): Bitmap = suspendCoroutine { continuation ->
val inputImage = InputImage.fromBitmap(bitmap, 0)
segmenter.process(inputImage)
.addOnSuccessListener { result ->
val maskBitmap = result.buffer.toMaskBitmap(bitmap.width, bitmap.height)
val outputBitmap = applyMask(bitmap, maskBitmap)
continuation.resume(outputBitmap)
}
.addOnFailureListener { e -> continuation.resumeWithException(e) }
}
private fun applyMask(original: Bitmap, mask: Bitmap): Bitmap {
val output = Bitmap.createBitmap(original.width, original.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
canvas.drawBitmap(original, 0f, 0f, paint)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
canvas.drawBitmap(mask, 0f, 0f, paint)
return output
}
private fun ByteBuffer.toMaskBitmap(width: Int, height: Int): Bitmap {
rewind()
val maskBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8)
maskBitmap.copyPixelsFromBuffer(this)
return maskBitmap
}
}
ML Kit Selfie Segmenter оптимізований для людей та селфі. Для довільних об'єктів — SubjectSegmenterOptions (доступно ML Kit 17+):
val options = SubjectSegmenterOptions.Builder()
.enableForegroundBitmap()
.build()
val segmenter = SubjectSegmentation.getClient(options)
Хмарні API для складних випадків
Коли на пристрої дає поганий результат (тонке волосся, прозорість, складний фон):
remove.bg API — спеціалізований сервіс, найкраща якість для волосся та дрібних деталей:
func removeBackgroundCloud(imageData: Data) async throws -> Data {
var request = URLRequest(url: URL(string: "https://api.remove.bg/v1.0/removebg")!)
request.httpMethod = "POST"
request.setValue(apiKey, forHTTPHeaderField: "X-Api-Key")
let boundary = UUID().uuidString
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var body = Data()
body.appendMultipart(boundary: boundary, name: "image_file", filename: "photo.jpg",
contentType: "image/jpeg", data: imageData)
body.appendMultipart(boundary: boundary, name: "size", data: "auto".data(using: .utf8)!)
body.append("--\(boundary)--\r\n".data(using: .utf8)!)
request.httpBody = body
let (data, response) = try await URLSession.shared.data(for: request)
// Відповідь — PNG з прозорим фоном
return data
}
Clipdrop API (Stability AI) — підтримує не лише людей, але й продукти, тварин.
PhotoRoom API — спеціалізація на продуктових фотографіях для e-commerce.
Архітектура: на пристрої + хмарна резервна копія
func removeBackground(_ image: UIImage) async -> UIImage {
// Спочатку пробуємо на пристрої
if let result = try? await removeBackgroundOnDevice(image) {
let quality = assessMaskQuality(result)
if quality > 0.85 { return result } // Маска хорошої якості
}
// Резервна копія на хмарі
guard let imageData = image.jpegData(compressionQuality: 0.9) else { return image }
if let cloudResult = try? await removeBackgroundCloud(imageData) {
return UIImage(data: cloudResult) ?? image
}
return image
}
private func assessMaskQuality(_ image: UIImage) -> Double {
// Оцінюємо якість маски за плавністю краю
// Простий евристика: співвідношення напівпрозорих до повністю прозорих пікселів
// Високе співвідношення = тонкі деталі = хороша якість
guard let cgImage = image.cgImage else { return 0 }
// ... аналіз пікселів маски
return 0.9 // заглушка
}
Постобробка маски
Після видалення фону часто потрібна доводка:
-
Feathering (розмиття краю) —
CIGaussianBlurна маці, радіус 1–2 пікселя - Erosion (звуження маски) — видаляє артефакти пікселів при краю
- Hair refinement — хмарні API краще справляються з тонким волоссям на пристрої
Терміни
На пристрої видалення фону (iOS VisionKit + Android ML Kit) з базовим UI — 3–4 дні. Хмарна резервна копія + оцінка якості маски + постобробка краю + експорт PNG — 8–10 днів.







