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

3.Objective-C++ 包装器
创建 CVWrapper.h, 实现具体的方法:
objective-c
#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;
@end
NS_ASSUME_NONNULL_END
创建 CVWrapper.mm:
objective-c
#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. 界面实现
swift
//
// ContentView.swift
// OpenCVDemo
//
import SwiftUI
struct 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 = 0
let 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 in
Text(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 in
UIColor.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: String
var 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: String
let title: String
let description: String
var 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作为布尔值。
解决办法:
调整头文件包含顺序,
objiective-c
// 先包含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>