【IOS开发】SwiftUI + OpenCV实现图片的简单处理(一)
以下是在 Xcode 中使用 OpenCV 的完整 Demo,包含多个实用的图像处理功能:
1. 项目设置和安装
使用 CocoaPods 安装 OpenCV,在Profile文件中添加:
platform :ios, '12.0'
use_frameworks!target 'OpenCVDemo' dopod 'OpenCV'
end
然后运行:
pod install
项目架构
OpenCVDemo/
├── OpenCVDemo-Bridging-Header.h
├── OpenCVDemoApp.swift
├── ContentView.swift
├── Tools/
│ ├── CVWrapper.h
│ ├── CVWrapper.mm
└── Resources/└── Assets.xcassets
2. 桥接头文件
Swift桥接OC,创建 Bridging-Header.h:
#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
在项目设置中设置桥接文件路径:
Build Settings → Swift Compiler - General → Objective-C Bridging Header

3.Objective-C++ 包装器
创建 CVWrapper.h, 实现具体的方法:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>NS_ASSUME_NONNULL_BEGIN
@interface CVWrapper : NSObject
// 基础图像处理
+ (UIImage *)convertToGray:(UIImage *)image;
+ (UIImage *)detectEdges:(UIImage *)image;
+ (UIImage *)applyBlur:(UIImage *)image;
+ (UIImage *)applySharpen:(UIImage *)image;// 工具方法
+ (NSString *)openCVVersion;@endNS_ASSUME_NONNULL_END
创建 CVWrapper.mm:
#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
#import <opencv2/videoio/cap_ios.h>
#import <opencv2/objdetect.hpp>
#import "CVWrapper.h"using namespace cv;
using namespace std;@implementation CVWrapper
// MARK: - 基础图像处理+ (UIImage *)convertToGray:(UIImage *)image {Mat inputImage;UIImageToMat(image, inputImage);Mat grayImage;if (inputImage.channels() == 1) {grayImage = inputImage;} else {cvtColor(inputImage, grayImage, COLOR_BGR2GRAY);cvtColor(grayImage, grayImage, COLOR_GRAY2BGR); // 转回BGR用于UIImage显示}return MatToUIImage(grayImage);
}+ (UIImage *)detectEdges:(UIImage *)image {Mat inputImage;UIImageToMat(image, inputImage);Mat gray, edges;cvtColor(inputImage, gray, COLOR_BGR2GRAY);GaussianBlur(gray, gray, cv::Size(5, 5), 1.5);Canny(gray, edges, 50, 150);cvtColor(edges, edges, COLOR_GRAY2BGR);return MatToUIImage(edges);
}+ (UIImage *)applyBlur:(UIImage *)image {Mat inputImage;UIImageToMat(image, inputImage);Mat blurred;GaussianBlur(inputImage, blurred, cv::Size(15, 15), 0);return MatToUIImage(blurred);
}+ (UIImage *)applySharpen:(UIImage *)image {Mat inputImage;UIImageToMat(image, inputImage);Mat sharpened;Mat kernel = (Mat_<double>(3,3) <<0, -1, 0,-1, 5, -1,0, -1, 0);filter2D(inputImage, sharpened, -1, kernel);return MatToUIImage(sharpened);
}// MARK: - 工具方法+ (NSString *)openCVVersion {return [NSString stringWithFormat:@"OpenCV Version: %s", CV_VERSION];
}@end
4. 界面实现
//
// ContentView.swift
// OpenCVDemo
//import SwiftUIstruct ContentView: View {@State private var selectedTab = 0@State private var openCVVersion = ""var body: some View {TabView(selection: $selectedTab) {// 标签1: 图像处理ImageProcessingView().tabItem {Image(systemName: "photo")Text("图像处理")}.tag(0)// 标签4: 关于AboutView(openCVVersion: openCVVersion).tabItem {Image(systemName: "info.circle")Text("关于")}.tag(3)}.onAppear {openCVVersion = CVWrapper.openCVVersion()}}
}// MARK: - 图像处理视图
struct ImageProcessingView: View {@State private var originalImage: UIImage? = UIImage(named: "sample_image")@State private var processedImage: UIImage?@State private var selectedFilter = 0let filters = ["原始图像","灰度化","边缘检测","模糊处理","锐化处理",]var body: some View {NavigationView {VStack(spacing: 20) {// 图像显示区域HStack(spacing: 20) {VStack {Text("原图").font(.headline)if let image = originalImage {Image(uiImage: image).resizable().scaledToFit().frame(height: 200).border(Color.gray, width: 1)} else {RoundedRectangle(cornerRadius: 8).fill(Color.gray.opacity(0.3)).frame(height: 200).overlay(Text("请选择图片"))}}VStack {Text("处理后").font(.headline)if let image = processedImage {Image(uiImage: image).resizable().scaledToFit().frame(height: 200).border(Color.blue, width: 2)} else {RoundedRectangle(cornerRadius: 8).fill(Color.blue.opacity(0.3)).frame(height: 200).overlay(Text("处理结果"))}}}.padding()// 滤镜选择Picker("选择滤镜", selection: $selectedFilter) {ForEach(0..<filters.count, id: \.self) { index inText(filters[index]).tag(index)}}.pickerStyle(SegmentedPickerStyle()).padding(.horizontal)// 处理按钮Button("应用处理") {applyFilter()}.buttonStyle(.borderedProminent).disabled(originalImage == nil)// 图片选择Button("选择图片") {// 在实际应用中,这里应该使用UIImagePickerController// 为演示目的,我们使用内置的示例图片loadSampleImage()}.buttonStyle(.bordered)Spacer()}.navigationTitle("OpenCV 图像处理").padding()}}private func applyFilter() {guard let image = originalImage else { return }switch selectedFilter {case 1:processedImage = CVWrapper.convert(toGray: image)case 2:processedImage = CVWrapper.detectEdges(image)case 3:processedImage = CVWrapper.applyBlur(image)case 4:processedImage = CVWrapper.applySharpen(image)default:processedImage = image}}private func loadSampleImage() {// 在实际应用中,这里应该从相册或相机获取图片// 这里我们创建一个简单的示例图片let renderer = UIGraphicsImageRenderer(size: CGSize(width: 300, height: 300))let image = renderer.image { context inUIColor.blue.setFill()context.fill(CGRect(x: 0, y: 0, width: 300, height: 300))UIColor.red.setFill()context.fill(CGRect(x: 50, y: 50, width: 100, height: 100))UIColor.green.setFill()context.fill(CGRect(x: 150, y: 150, width: 100, height: 100))}originalImage = UIImage(named: "sample")processedImage = nil}
}// MARK: - 关于视图
struct AboutView: View {let openCVVersion: Stringvar body: some View {NavigationView {VStack(spacing: 20) {Image(systemName: "camera.filters").font(.system(size: 80)).foregroundColor(.blue)Text("OpenCV Swift Demo").font(.largeTitle).fontWeight(.bold)Text(openCVVersion).font(.title2).foregroundColor(.secondary)VStack(alignment: .leading, spacing: 15) {FeatureRow(icon: "photo", title: "图像处理", description: "灰度化、边缘检测、模糊、锐化")FeatureRow(icon: "camera", title: "实时处理", description: "相机实时OpenCV处理")FeatureRow(icon: "face.smiling", title: "人脸检测", description: "基于Haar级联的人脸检测")FeatureRow(icon: "square.and.arrow.down", title: "结果保存", description: "保存处理后的图片")}.padding()Spacer()Text("使用Swift和OpenCV构建").font(.caption).foregroundColor(.secondary)}.padding().navigationTitle("关于")}}
}struct FeatureRow: View {let icon: Stringlet title: Stringlet description: Stringvar body: some View {HStack {Image(systemName: icon).font(.title2).foregroundColor(.blue).frame(width: 40)VStack(alignment: .leading) {Text(title).font(.headline)Text(description).font(.caption).foregroundColor(.secondary)}Spacer()}}
}// MARK: - 预览
struct ContentView_Previews: PreviewProvider {static var previews: some View {ContentView()}
}
运行效果图
图片进行灰度处理

图片进行“边缘检测”处理

图片进行“模糊处理”

图像进行“锐化处理
”
遇到的问题
1.问题一
Detected Apple 'NO' macro definition, it can cause build conflicts. Please, include this header before any Apple headers.
错误原因:
这个警告是因为OpenCV和Apple的SDK都定义了NO宏,导致冲突。OpenCV使用NO表示"Not OpenCV",而Apple的SDK使用NO作为布尔值。
解决办法:
调整头文件包含顺序,
// 先包含OpenCV头文件
#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
#import <opencv2/videoio/cap_ios.h>// 然后包含Foundation
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
