iOS使用攝像頭實時掃描,并實時提取文字

實現(xiàn)通過攝像頭實時掃描并將識別的文字實時疊加在屏幕上的效果,可以結(jié)合 Apple 的 AVFoundation 和 Vision 框架完成笆制。以下是完整實現(xiàn)步驟:

功能描述

使用 AVCaptureSession 打開攝像頭捕獲實時視頻流。
使用 Vision 框架 的 VNRecognizeTextRequest 對每一幀視頻進行文字識別涣达。
將識別到的文字疊加顯示在屏幕上的 UILabel 中在辆。

實現(xiàn)代碼

import UIKit
import AVFoundation
import Vision

class LiveTextRecognitionViewController: UIViewController {
    
    private var captureSession: AVCaptureSession!
    private var previewLayer: AVCaptureVideoPreviewLayer!
    private var detectedTextLabel: UILabel!
    private var textRequest: VNRecognizeTextRequest!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        
        // 配置攝像頭
        setupCamera()
        
        // 配置實時顯示的 UILabel
        setupDetectedTextLabel()
        
        // 配置 Vision 請求
        setupTextRecognitionRequest()
    }
    
   private func setupCamera() {
    captureSession = AVCaptureSession()
    captureSession.sessionPreset = .high
    
    guard let videoDevice = AVCaptureDevice.default(for: .video),
          let videoInput = try? AVCaptureDeviceInput(device: videoDevice) else {
        print("無法訪問攝像頭")
        return
    }
    
    if captureSession.canAddInput(videoInput) {
        captureSession.addInput(videoInput)
    }
    
    let videoOutput = AVCaptureVideoDataOutput()
    videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoFrameProcessingQueue"))
    
    if captureSession.canAddOutput(videoOutput) {
        captureSession.addOutput(videoOutput)
    }
    
    // 設置預覽圖層
    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    previewLayer.videoGravity = .resizeAspectFill
    previewLayer.frame = view.bounds
    view.layer.addSublayer(previewLayer)
    
    // 將 startRunning 放到后臺線程
    DispatchQueue.global(qos: .background).async {
        self.captureSession.startRunning()
    }
}

    private func setupDetectedTextLabel() {
        detectedTextLabel = UILabel()
        detectedTextLabel.numberOfLines = 0
        detectedTextLabel.textColor = .yellow
        detectedTextLabel.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        detectedTextLabel.textAlignment = .center
        detectedTextLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(detectedTextLabel)
        
        NSLayoutConstraint.activate([
            detectedTextLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            detectedTextLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            detectedTextLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -40),
            detectedTextLabel.heightAnchor.constraint(equalToConstant: 120)
        ])
    }
    
    private func setupTextRecognitionRequest() {
        textRequest = VNRecognizeTextRequest { [weak self] (request, error) in
            guard let self = self else { return }
            if let error = error {
                print("文本識別出錯: \(error)")
                return
            }
            self.processTextRecognitionResults(request.results)
        }
        textRequest.recognitionLevel = .accurate
        textRequest.recognitionLanguages = ["en-US", "zh-Hans"]
        textRequest.usesLanguageCorrection = true
    }
    
    private func processTextRecognitionResults(_ results: [Any]?) {
        guard let results = results as? [VNRecognizedTextObservation] else { return }
        
        let detectedText = results.compactMap { observation in
            observation.topCandidates(1).first?.string
        }.joined(separator: "\n")
        
        DispatchQueue.main.async {
            self.detectedTextLabel.text = detectedText.isEmpty ? "未檢測到文字" : detectedText
        }
    }
}

extension LiveTextRecognitionViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
        
        let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: .up, options: [:])
        do {
            try handler.perform([textRequest])
        } catch {
            print("文本識別請求處理失敗: \(error)")
        }
    }
}

代碼解析

AVCaptureSession:
AVCaptureSession 用于實時捕獲攝像頭視頻流。
使用 AVCaptureVideoDataOutput 捕獲每一幀視頻并進行處理度苔。

Vision Text Recognition:
配置 VNRecognizeTextRequest 以進行文字識別匆篓。
支持多語言識別:配置 recognitionLanguages 為 ["en-US", "zh-Hans"],同時支持中文和英文寇窑。

實時顯示文本:
將識別到的文字拼接成字符串鸦概,通過 UILabel 動態(tài)更新到屏幕上。

線程處理:
使用 DispatchQueue 在后臺處理視頻幀甩骏。
通過 DispatchQueue.main.async 更新 UI窗市,確保線程安全。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饮笛,一起剝皮案震驚了整個濱河市咨察,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缎浇,老刑警劉巖扎拣,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異素跺,居然都是意外死亡二蓝,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門指厌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刊愚,“玉大人,你說我怎么就攤上這事踩验∨阜蹋” “怎么了商玫?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長牡借。 經(jīng)常有香客問我拳昌,道長,這世上最難降的妖魔是什么钠龙? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任炬藤,我火速辦了婚禮,結(jié)果婚禮上碴里,老公的妹妹穿的比我還像新娘沈矿。我一直安慰自己,他們只是感情好咬腋,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布羹膳。 她就那樣靜靜地躺著,像睡著了一般根竿。 火紅的嫁衣襯著肌膚如雪陵像。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天犀填,我揣著相機與錄音蠢壹,去河邊找鬼。 笑死九巡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蹂季。 我是一名探鬼主播冕广,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼偿洁!你這毒婦竟也來了撒汉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤涕滋,失蹤者是張志新(化名)和其女友劉穎睬辐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宾肺,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡溯饵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了锨用。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丰刊。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖增拥,靈堂內(nèi)的尸體忽然破棺而出啄巧,到底是詐尸還是另有隱情寻歧,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布秩仆,位于F島的核電站码泛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏澄耍。R本人自食惡果不足惜弟晚,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望逾苫。 院中可真熱鬧卿城,春花似錦、人聲如沸铅搓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽星掰。三九已至多望,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氢烘,已是汗流浹背怀偷。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留播玖,地道東北人椎工。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像蜀踏,于是被迫代替她去往敵國和親维蒙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355