CoreImage เป็นเฟรมเวิร์กของ Apple สำหรับการประมวลผลภาพและวิดีโอแบบเรียลไทม์ ให้ตัวกรอง CIFilter ในตัวมากมายสำหรับการแก้ไขสี การเบลอ การตั้งชั้นพื้นผิวและการตรวจจับ ตามที่ระบุไว้ใน เอกสาร Apple CoreImage ใช้ GPU สำหรับการประมวลผลพิกเซลประสิทธิภาพสูงบนอุปกรณ์ iOS เฟรมเวิร์ก รองรับ CIImage เป็นอ็อบเจกต์รูปภาพที่ไม่สามารถเปลี่ยนแปลงได้ และโซ่อินเฟลเตอร์สำหรับการประกอบเอฟเฟกต์โดยไม่สูญเสียคุณภาพ
ข้อสำคัญ
CoreImage เป็นเฟรมเวิร์กของ Apple สำหรับการประมวลผลภาพแรสเตอร์และวิดีโอ เปิดตัวครั้งแรกใน macOS 10.4 Tiger และถูกย้ายไปยัง iOS 5.0 ต่างจาก Core Graphics หรือ UIKit CoreImage ทำงานในระดับพิกเซลเชเดอร์ โดยใช้ GPU สำหรับการคำนวณแบบขนาน ทำให้สามารถใช้เอฟเฟกต์ที่ซับซ้อน ไม่ว่าจะเป็นการเบลอ การแก้ไขสี การเปลี่ยนรูปร่าง กับภาพที่มีความละเอียดระดับเมกะพิกเซลได้ภายในไมโครวินาที
สถาปัตยกรรมของ CoreImage สร้างบนแนวคิดของการประเมินแบบขี้เกียจ (lazy evaluation): CIFilter จะไม่ประมวลผลจนกว่าจะมีการเรนเดอร์ใน CIContext นักพัฒนาสร้างโซ่ของ CIFilter หลายๆ ตัว โดยเชื่อมต่อเอาต์พุตของตัวกรองหนึ่งไปยังอินพุตของอีกตัวหนึ่ง และเฉพาะการเรียก render เท่านั้นที่จะเริ่มต้นสายท่อ GPU เต็มรูปแบบ ซึ่งสามารถลดจำนวนผ่านการ์ดจอและรักษาประสิทธิภาพ
CoreImage รองรับ ช่วงสีกว้าง (P3, sRGB, sRGB เชิงเส้นตรง), ภาพ HDR และการทำงานกับรูปแบบพิกเซลแบบ 16 บิตและ 32 บิต บนอุปกรณ์ที่มี Neural Engine CoreImage สามารถรวม GPU shader กับ Core ML สำหรับการประมวลผลอย่างชาญฉลาด เช่น การแก้ไขสีอัตโนมัติโดยอาศัยการเรียนรู้ของเครื่อง อย่างที่นำไปใช้ในแอพรูปภาพบน iOS 17
สามคลาสหลัก ประกอบเป็นแกนของ CoreImage: CIImage (ข้อมูล), CIFilter (การดำเนินการ) และ CIContext (สภาพแวดล้อมการทำงาน) แต่ละคลาสรับผิดชอบต่อระยะผลิตผลของตัวเอง และไม่ปนความรับผิดชอบ
CIImage เป็นอ็อบเจกต์ที่มีน้ำหนักเบา ซึ่งอธิบายภาพแต่ไม่มีข้อมูลพิกเซลโดยตรง สามารถสร้างจาก UIImage, CGImage, เนื้อเกล Metal, เนื้อเกล GL หรือไฟล์บนดิสก์ CIImage ไม่สามารถเปลี่ยนแปลงได้ การใช้ตัวกรองใดๆ จะสร้าง CIImage ใหม่โดยไม่แก้ไขของต้นฉบับ ซึ่งทำให้สามารถสร้างโซ่การแปลงรูปโดยไม่ต้องคัดลอกข้อมูลระหว่างขั้นตอน
คุณสมบัติที่สำคัญ: CIImage ไม่ถูกผูกมัดกับความละเอียดหน้าจอหรือพื้นที่สีก่อนการเรนเดอร์ CIImage เดียวกันสามารถเรนเดอร์เป็น UIImage สำหรับหน้าจอ และเป็นไฟล์ TIFF สำหรับการพิมพ์โดยใช้พารามิเตอร์ที่ต่างกัน โดย CoreImage จะปรับการประมวลผลให้เหมาะสมกับบริบทเป้าหมายโดยอัตโนมัติ
CIFilter เป็นคลาสหลักสำหรับการใช้เอฟเฟกต์ แต่ละ CIFilter เป็นโปรแกรม shader ที่มีพารามิเตอร์ขาเข้า (inputImage, inputIntensity, inputRadius และอื่นๆ) และภาพขาออกหนึ่งภาพ Apple มี CIFilter ในตัวมากกว่า 200 รายการ แบ่งกลุ่มตามหมวดหมู่: CICategoryColorEffect (การแก้ไขสี), CICategoryBlur (การเบลอ), CICategoryStylize (การจัดรูปแบบ), CICategoryGeometryAdjust (การแปลงทางเรขาคณิต)
การสร้าง CIFilter ที่กำหนดเอง นักพัฒนาต้องเขียน Metal shader (CIKernel) ซึ่งเป็น fragment shader ในภาษา Metal Shading Language ที่ประมวลผลแต่ละพิกเซลอย่างอิสระ หลังจากการคอมไพล์ shader จะถูกลงทะเบียนเป็นคลาสย่อยของ CIFilter และสามารถใช้ในโซ่ร่วมกับตัวกรองในตัวของ Apple
| หมวดหมู่ | ตัวอย่างตัวกรอง | วัตถุประสงค์ |
|---|---|---|
| ColorEffect | CIColorControls | ความสว่าง, ความเปรียบต่าง, ความอิ่มตัว |
| Blur | CIGaussianBlur | การเบลอแบบเกาเซียนที่มีรัศมีที่สามารถปรับได้ |
| Stylize | CIPixellate | การทำให้ภาพเป็นพิกเซลตามมาตราที่กำหนด |
| GeometryAdjust | CIAffineTransform | การหมุน, การเปลี่ยนขนาด, การเลื่อนตำแหน่งผ่าน affine matrix |
| Composite | CISourceOverCompositing | การรวมภาพด้วยช่องอัลฟา |
CIContext เป็นอ็อบเจกต์หนักที่จัดการจัดสรรทรัพยากร GPU, การคอมไพล์ shader และการบัฟเฟอร์ การสร้าง CIContext เป็นการดำเนินการที่มีต้นทุนสูง ดังนั้น Apple แนะนำให้สร้างมันครั้งเดียวตลอดวงจรของแอปพลิเคชันและใช้ซ้ำ บริบทถูกผูกมัดกับ GPU (Metal, OpenGL) หรือ CPU เฉพาะเจาะจง และกำหนดพื้นที่สีของภาพขาออก
ไลบรารี CIFilter ขยายตัวอย่างต่อเนื่อง iOS 17 เพิ่มตัวกรองใหม่สำหรับการประมวลผล HDR และการเรียนรู้ของเครื่อง ตัวกรองในตัวทั้งหมดมีเอกสารอยู่ในเอกสารนักพัฒนา Apple และสามารถค้นหาตามหมวดหมู่หรือชื่อได้ หากต้องการค้นหาตัวกรองที่มีอยู่ในอุปกรณ์ ให้ใช้ CIFilter.filterNames(inCategory:)
ความสามารถหลัก ของ CoreImage คือการประกอบ CIFilter หลายๆ ตัวเข้าด้วยกันเป็นโซ่ เอาต์พุตของตัวกรองหนึ่งจะถูกป้อนไปยังอินพุตของอีกตัวหนึ่งผ่านพารามิเตอร์ inputImage CoreImage จะปรับปรุงโซ่ในขั้นตอนการเรนเดอร์: ตัวกรองที่อยู่ติดกันซึ่งทำงานในพื้นที่สีเดียวกันจะถูกรวมเป็น GPU pass เดียว (kernel fusion) ซึ่งช่วยเพิ่มประสิทธิภาพโดยไม่ต้องให้นักพัฒนาเข้าไปแทรกแซง
การสร้าง เอฟเฟกต์ที่กำหนดเอง นักพัฒนาต้องเขียนฟังก์ชัน Metal โดยใช้คำอธิบาย [[kernel]] ฟังก์ชันจะรับพิกัดพิกเซลและส่งค่าสีกลับไป CoreImage จะส่ง shader ไปยัง GPU ซึ่งจะทำงานแบบขนานสำหรับพิกเซลทั้งหมดของภาพ ตัวกรองที่กำหนดเองมีประโยชน์โดยเฉพาะสำหรับเอฟเฟกต์ทางสายตาที่เป็นเอกลักษณ์ เช่น ภาพสีเซเปียที่มีเส้นโค้งไม่เป็นเส้นตรง การเบลอแบบกระจาย หรือการจำลองเม็ดฟิล์ม
#include <CoreImage/CoreImage.h>
[[kernel]] float4 customFilter(sample_t s, float intensity) {
float4 result;
result.rgb = s.rgb * (1.0 - intensity) + s.r * intensity;
result.a = s.a;
return result;
}
CoreImage จัดการแคชของผลลัพธ์กลางโดยอัตโนมัติ หากใช้โซ่ตัวกรองเดียวกันกับภาพที่ต่างกัน CoreImage สามารถใช้ shader ที่คอมไพล์แล้วซ้ำได้ สำหรับประสิทธิภาพสูงสุด หลีกเลี่ยงการสร้าง CIContext ในแต่ละเฟรม ให้ใช้บริบทเดียวและรีเซ็ตพารามิเตอร์ขาเข้าของตัวกรอง
CIDetector เป็นระบบย่อยของ CoreImage สำหรับการตรวจจับวัตถุทางความหมายในภาพโดยไม่ต้องใช้ Vision หรือ Core ML CIDetector รองรับการตรวจจับสี่ประเภท: ใบหน้า (CIDetectorTypeFace), ข้อความ (CIDetectorTypeText), QR code (CIDetectorTypeQRCode) และสี่เหลี่ยม (CIDetectorTypeRectangle) ตัวตรวจจับทำงานบน CPU โดยมีการปรับแต่งสำหรับคำสั่ง NEON ทำให้มีความเร็วคงที่แม้ในอุปกรณ์ที่ไม่มี GPU ที่แรง
ตัวตรวจจับใบหน้า CIDetectorTypeFace จะส่งคืนอาร์เรย์ของ CIFaceFeature ที่มีพิกัดขอบใบหน้า ตำแหน่งดวงตาและปาก ตั้งแต่ iOS 12 CIDetector ยังสามารถตรวจจับรอยยิ้ม (hasSmile) และตำแหน่งของตาซ้าย/ขวา (leftEyeClosed, rightEyeClosed) ความแม่นยำในการตรวจจับเพียงพอสำหรับแอป AR และภาพถ่ายส่วนใหญ่ แต่สำหรับสถานการณ์ที่สำคัญ Apple แนะนำให้ใช้ Vision.framework
CIDetectorTypeRectangle ค้นหาบริเวณสี่เหลี่ยมในภาพ ไม่ว่าจะเป็นเอกสาร นามตราภิพัฒน์ หรือหน้าจอของอุปกรณ์ ตัวตรวจจับจะส่งคืน CIRectangleFeature ที่มีสี่จุดซึ่งประกอบเป็นเส้นโค้งของสี่เหลี่ยม ตามที่ระบุไว้ใน WWDC 2024 ตัวตรวจจับสี่เหลี่ยมใช้สถาปัตยกรรมเครือข่ายประสาทเดียวกับ Vision แต่ใช้หน่วยความจำน้อยกว่า ทำให้เหมาะสมสำหรับการประมวลผลสตรีมเฟรมแบบเรียลไทม์ เช่น ในแอปพลิเคชันสแกนเอกสาร
ตัวอย่างที่ละเอียดฝึกฝน จะช่วยเสริมความเข้าใจ CoreImage มาดูสองสถานการณ์ทั่วไป: การใช้ตัวกรองสีกับภาพถ่ายและการตรวจจับใบหน้าโดยใช้การวาดกรอบแนวบอก
ตัวอย่างพื้นฐานของตัวกรอง CISepiaTone ซึ่งแปลงภาพสีเป็นโทนสีเซเปีย ตัวกรองรับพารามิเตอร์ inputIntensity ตั้งแต่ 0 (ต้นฉบับ) ถึง 1 (ผลกระทบสูงสุด) โปรดสังเกตการประเมินแบบขี้เกียจ: CIImage ที่ filter.outputImage ส่งกลับมาไม่มีพิกเซล แต่การเรนเดอร์จะเกิดขึ้นเมื่อมีการเรียก context.createCGImage
import CoreImage
guard let inputImage = CIImage(image: uiImage) else { return }
let filter = CIFilter(name: "CISepiaTone")
filter?.setValue(inputImage, forKey: kCIInputImageKey)
filter?.setValue(0.8, forKey: kCIInputIntensityKey)
let context = CIContext()
let outputImage = filter?.outputImage
let cgImage = context.createCGImage(outputImage!, from: inputImage.extent)
let resultImage = UIImage(cgImage: cgImage!)
ตัวอย่างต่อไปนี้ใช้ CIDetector ในการค้นหาใบหน้าในภาพและวาดเป็นสี่เหลี่ยมรอบๆ ใบหน้าที่ตรวจจับพบ โดย CIFaceFeature จะมีพิกัดในระบบพิกัดภาพ (จุดกำเนิดอยู่มุมล่างซ้าย) ดังนั้นเมื่อวาดบน UIKit จึงต้องมีการแปลงพิกัดโดยใช้ affine transform
let detector = CIDetector(
ofType: CIDetectorTypeFace,
context: context,
options: [CIDetectorAccuracy: CIDetectorAccuracyHigh]
)
let features = detector?.features(in: inputImage) as? [CIFaceFeature]
for face in features ?? [] {
print("Face bounds: \(face.bounds)")
if face.hasSmile {
print("บุคคลกำลังยิ้ม")
}
}
ตัวอย่างสุดท้ายแสดงให้เห็น โซ่ของสามตัวกรอง: การแก้ไขสี, การใส่มุมมืด และการตั้งชั้นพื้นผิว โปรดสังเกตว่า outputImage ของตัวกรองตัวแรกถูกส่งต่อเป็น inputImage ให้กับตัวที่สอง โดยไม่มีการเรนเดอร์ขั้นกลาง เมื่อเรียก createCGImage CoreImage จะรวมการดำเนินการทั้งสามเข้าด้วยกันเป็น GPU pass เดียว
let colorFilter = CIFilter(name: "CIColorControls")
colorFilter?.setValue(inputImage, forKey: kCIInputImageKey)
colorFilter?.setValues([
kCIInputBrightnessKey: 0.1,
kCIInputContrastKey: 1.2
])
let vignetteFilter = CIFilter(name: "CIVignette")
vignetteFilter?.setValue(colorFilter?.outputImage, forKey: kCIInputImageKey)
vignetteFilter?.setValue(2.0, forKey: "inputRadius")
let finalImage = vignetteFilter?.outputImage
let result = context.createCGImage(finalImage!, from: inputImage.extent)
คำถามที่พบบ่อย
CoreImage ทำงานบน GPU และได้รับการปรับแต่งสำหรับการดำเนินการกับพิกเซล (ตัวกรอง, การแก้ไขสี) ในขณะที่ Core Graphics เป็นไลบรารี CPU สำหรับการวาดเวกเตอร์และบริบทสองมิติ CoreImage เร็วกว่าสำหรับการประมวลผลภาพจำนวนมาก Core Graphics แม่นยำกว่าสำหรับการวาดส่วนติดต่อทีละส่วน
ได้ — CoreImage รองรับการประมวลผลเฟรมวิดีโอแต่ละเฟรมผ่าน AVPlayerItemVideoOutput หรือ AVCaptureOutput สำหรับการประมวลผลแบบสตรีมให้ใช้ AVVideoComposition ร่วมกับ CIFilter ซึ่งจะช่วยให้สามารถใช้เอฟเฟกต์โดยไม่ต้องคัดลอกเฟรมระหว่าง CPU และ GPU
CoreImage ใช้งานในพื้นที่สีทำงาน sRGB (kCGColorSpaceSRGB) เป็นค่าเริ่มต้น เมื่อสร้าง CIContext คุณสามารถระบุพื้นที่สีที่เลือกได้ เช่น sRGB เชิงเส้นตรงแบบขยายสำหรับ HDR หรือ Display P3 สำหรับหน้าจอช่วงสีกว้าง
ไม่มีข้อจำกัดจำนวนตัวกรองในโซ่ แต่ทุก 5-7 ตัวกรองต่อเนื่องจะสร้าง GPU pass เพิ่มเติม สำหรับมากกว่า 10 ตัวกรอง ควรแยกโซ่เป็นกลุ่ม และเรนเดอร์ผลลัพธ์กลางเพื่อหลีกเลี่ยงเกินขอบตารีจีสเตอร์ shader
ได้ — CIDetector ทำงานบน CPU โดยใช้คำสั่ง NEON บนอุปกรณ์ทั้งหมดที่ใช้ iOS 5.0 ขึ้นไป ความแม่นยำในการตรวจจับเหมือนกันในทุกอุปกรณ์ แต่ความเร็วจะสูงกว่าในชิป Apple A12+ เนื่องจากเครือข่ายประสาทที่เร่งด้วยฮาร์ดแวร์
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ