ARSCNView使用
swift
var sceneView: ARSCNView = ARSCNView(frame: UIScreen.main.bounds)
let configuartion = ARWorldTrackingConfiguration()
//会话session ARSessionDelegate 会话状态更新相关代理方法
sceneView.session.delegate = self
//ARSCNViewDelegate 节点场景管理相关代理方法
sceneView.delegate = self
// 自动对焦开启
configuartion.isAutoFocusEnabled = true
//平面检测方向
configuartion.planeDetection = .horizontal
//光线估计
configuartion.isLightEstimationEnabled = true
/*
使用提供的配置运行会话,
resetTracking 移动到新环境重新扫描追踪
*/
sceneView.session.run(configuartion, options: [.resetTracking,.removeExistingAnchors])
//调试参数
sceneView.debugOptions = [SCNDebugOptions.showFeaturePoints]
1 加载立体模型
3d模型网站
https://sketchfab.com/3d-models/coin-d41feb2c10ed4c06ad4b8134ccaba516 自己上去找模型
加载这个模型到场景中
kotlin
sceneView.scene = SCNScene(named: "ship.scn", inDirectory: "models.scnassets/ship") ?? SCNScene()
2 识别图片
kotlin
var images :[UIImage] = []
for i in 1...19{
let image = UIImage(named: "AR\(i)")
images.append(image!)
}
configuartion.detectionImages = loadedImagesFromDirectoryContents(images)
//其实可以直接加载图片文件的,这样图片直接转ARSet更直接一点
func loadedImagesFromDirectoryContents(_ images: [UIImage]) -> Set<ARReferenceImage>{
var index = 0
var customReferenceSet = Set<ARReferenceImage>()
images.forEach { (downloadedImage) in
//1. Convert The UIImage To A CGImage
guard let cgImage = downloadedImage.cgImage else { return }
//2. Get The Width Of The Image
let imageWidth = CGFloat(cgImage.width)
//3. Create A Custom AR Reference Image With A Unique Name
let customARReferenceImage = ARReferenceImage(cgImage, orientation: CGImagePropertyOrientation.up, physicalWidth: imageWidth)
customARReferenceImage.name = "MyCustomARImage\(index)"
//4. Insert The Reference Image Into Our Set
customReferenceSet.insert(customARReferenceImage)
print("ARReference Image == \(customARReferenceImage)")
index += 1
}
//5. Return The Set
return customReferenceSet
}
//在ARSCNViewDelegate方法里
func renderer(_ renderer: any SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
if let imageAnchor = anchor as? ARImageAnchor{
let image = imageAnchor.referenceImage
if let imagename = image.name, imagename.hasPrefix("AR"){
print("识别出来图片")
}
}
//加载3d数据识别出来立体物体,具体如下
if let objectAnchor = anchor as? ARObjectAnchor {
print("Detected object: \(objectAnchor.referenceObject.name ?? "Unknown")")
}
}
视觉算法 Vision识别
kotlin
//获取当前会话帧数据
func getCurrentFrameImage(from session: ARSession) -> UIImage? {
guard let currentFrame = session.currentFrame else {
print("当前没有 ARFrame")
return nil
}
let pixelBuffer = currentFrame.capturedImage
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let context = CIContext()
guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {
return nil
}
return UIImage(cgImage: cgImage)
}
func matchImages(image1: UIImage, image2: UIImage, completion: @escaping (Bool) -> Void) {
guard let cgImage1 = image1.cgImage, let cgImage2 = image2.cgImage else {
completion(false)
return
}
let request1 = VNGenerateImageFeaturePrintRequest()
let request2 = VNGenerateImageFeaturePrintRequest()
let request3 = VNDetectRectanglesRequest()
request3.minimumConfidence = 0.8
request3.minimumAspectRatio = 0.1
request3.maximumAspectRatio = 1.0
request3.quadratureTolerance = 10
let handler1 = VNImageRequestHandler(cgImage: cgImage1, options: [:])
let handler2 = VNImageRequestHandler(cgImage: cgImage2, options: [:])
let handler3 = VNImageRequestHandler(cgImage: cgImage1, options: [:])
do {
try handler1.perform([request1])
try handler2.perform([request2])
try handler3.perform([request3])
guard let featurePrint1 = request1.results?.first as? VNFeaturePrintObservation,
let featurePrint2 = request2.results?.first as? VNFeaturePrintObservation else {
completion(false)
return
}
if let observations = request3.results as? [VNRectangleObservation], !observations.isEmpty{
// 假设目标区域是第一个匹配的矩形
let boundingBox = observations.first?.boundingBox
print("boundRext: \(boundingBox)")
}
var distance: Float = 0
try featurePrint1.computeDistance(&distance, to: featurePrint2)
print("匹配值 \(distance)")
completion(distance < 0.8) // 设定相似度阈值
} catch {
print("匹配失败:\(error)")
completion(false)
}
}
//当前数据和所有图片集对比
func handleFrame(session: ARSession,frame: ARFrame){
let i = frame.timestamp - (self.currentFrmae?.timestamp ?? 0)
// print("time i\(i)")
if i < 1{
return
}
self.currentFrmae = frame
guard let frameImg = getCurrentFrameImage(from: session) else{return}
var isMatched:Bool = false
for img in self.images{
// if compareImages(image1: frameImg, image2: img) == 1{
// isMatched = true
// break
// }
let im1 = frameImg
let im2 = img
matchImages(image1: frameImg, image2: img) { [weak self]isok in
if isok{
DispatchQueue.main.async {
self?.showToast()
}
}
}
}
}