AVFoundation
を使用して、デバイスのカメラでQRコードをスキャンできることを知っています。ここで問題が発生しました。静的UIImage
オブジェクトからこれを行うにはどうすればよいですか?
IOS APIは、CoreImageフレームワークからCIDetectorクラスを提供します。 CIDetectorを使用すると、顔、笑顔、目、または私たちの場合はQRコードなど、画像内の特定のパターンを見つけることができます。
Objective-CのUIImageからQRCodeを検出するコードは次のとおりです。
-(NSArray *)detectQRCode:(UIImage *) image
{
@autoreleasepool {
NSLog(@"%@ :: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
NSCAssert(image != nil, @"**Assertion Error** detectQRCode : image is nil");
CIImage* ciImage = image.CIImage; // assuming underlying data is a CIImage
//CIImage* ciImage = [[CIImage alloc] initWithCGImage: image.CGImage];
// to use if the underlying data is a CGImage
NSDictionary* options;
CIContext* context = [CIContext context];
options = @{ CIDetectorAccuracy : CIDetectorAccuracyHigh }; // Slow but thorough
//options = @{ CIDetectorAccuracy : CIDetectorAccuracyLow}; // Fast but superficial
CIDetector* qrDetector = [CIDetector detectorOfType:CIDetectorTypeQRCode
context:context
options:options];
if ([[ciImage properties] valueForKey:(NSString*) kCGImagePropertyOrientation] == nil) {
options = @{ CIDetectorImageOrientation : @1};
} else {
options = @{ CIDetectorImageOrientation : [[ciImage properties] valueForKey:(NSString*) kCGImagePropertyOrientation]};
}
NSArray * features = [qrDetector featuresInImage:ciImage
options:options];
return features;
}
}
QRCodeが存在し検出された場合、返されたNSArray*
にはCIFeature*
が含まれます。 QRCodeがない場合、NSArray*
はnil
になります。 QRCodeのデコードが失敗した場合、NSArray*
には要素がありません。
エンコードされた文字列を取得するには:
if (features != nil && features.count > 0) {
for (CIQRCodeFeature* qrFeature in features) {
NSLog(@"QRFeature.messageString : %@ ", qrFeature.messageString);
}
}
@ Duncan-Cの回答のように、QRCodeのコーナーを抽出して、QRCodeを囲むバウンディングボックスを画像上に描画できます。
注:iOS10.0ベータ6では、cameraSampleBufferからの画像を使用する場合の[qrDetector featuresInImage:ciImage options:options]
の呼び出しにより、この内部警告がログに記録されます(スムーズに実行されます)しかし、このメッセージでコンソールをスパムし、私は今のところそれを取り除く方法を見つけることができませんでした):
ロックカウントが1のときのCVPixelBuffer 0x170133e20のファイナライズ。
出典:
@NeimszのSwift 4バージョン answer
func detectQRCode(_ image: UIImage?) -> [CIFeature]? {
if let image = image, let ciImage = CIImage.init(image: image){
var options: [String: Any]
let context = CIContext()
options = [CIDetectorAccuracy: CIDetectorAccuracyHigh]
let qrDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: options)
if ciImage.properties.keys.contains((kCGImagePropertyOrientation as String)){
options = [CIDetectorImageOrientation: ciImage.properties[(kCGImagePropertyOrientation as String)] ?? 1]
}else {
options = [CIDetectorImageOrientation: 1]
}
let features = qrDetector?.features(in: ciImage, options: options)
return features
}
return nil
}
使い方
if let features = detectQRCode(#imageLiteral(resourceName: "qrcode")), !features.isEmpty{
for case let row as CIQRCodeFeature in features{
print(row.messageString ?? "nope")
}
}
そして実行中にこれはFinalizing CVPixelBuffer 0x170133e20 while lock count is 1
を生成しません
次のQRCode画像を使用しました(QRCode = https://jingged.com )
(iOSバージョン11.2のiPhone 6シミュレータでテスト済み)
出力:
2018-03-14 15:31:13.159400+0530 TestProject[25889:233062] [MC] Lazy loading NSBundle MobileCoreServices.framework
2018-03-14 15:31:13.160302+0530 TestProject[25889:233062] [MC] Loaded MobileCoreServices.framework
https://jingged.com
Core ImageにはCIDetector
クラスがあり、QRコードを検出するためのCIDetectorTypeQRCode
があります。コアイメージフィルターには、静止画像またはビデオをフィードできます。
それはあなたのニーズを満たすはずです。詳細については、Xcodeのドキュメントを参照してください。
Github repo iOS8-day-by-day のShinobiControlsには、CIDetectorTypeQRCodeの使用方法を示すプロジェクトLiveDetectionが含まれています。ビデオフィードと静止画像から。 Swift 2.0では更新されていないようです。Xcode7.2.1でコンパイルすることはできませんでしたが、関数performQRCodeDetection
プロジェクトはコンパイルします(コンパイルの問題は、SwiftでCVPixelBuffers
を処理するために処理しなければならないすべての恐ろしい型キャストを処理するコードにあります。これは、QRCodesを見つけるだけでかまいません。静止画像。)
これがそのサイトの主要なメソッドです(Swift)
func performQRCodeDetection(image: CIImage) -> (outImage: CIImage?, decode: String) {
var resultImage: CIImage?
var decode = ""
if let detector = detector {
let features = detector.featuresInImage(image)
for feature in features as! [CIQRCodeFeature] {
resultImage = drawHighlightOverlayForPoints(image,
topLeft: feature.topLeft,
topRight: feature.topRight,
bottomLeft: feature.bottomLeft,
bottomRight: feature.bottomRight)
decode = feature.messageString
}
}
return (resultImage, decode)
}
テストメッセージを返すことに関して、ここでの答えはどれも非常に簡単ではありませんでした。私にとってうまくいく小さな拡張を作りました:
https://Gist.github.com/freak4pc/3f7ae2801dd8b7a068daa957463ac645
extension UIImage {
func parseQR() -> [String] {
guard let image = CIImage(image: self) else {
return []
}
let detector = CIDetector(ofType: CIDetectorTypeQRCode,
context: nil,
options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])
let features = detector?.features(in: image) ?? []
return features.compactMap { feature in
return (feature as? CIQRCodeFeature)?.messageString
}
}
}
ZbarSDKを使用して、静的画像からQRコードを読み取ります。
Zbar SDKの起動については、このチュートリアルを確認してください。
そして、静止画像をスキャンしてみます。
Zbarスキャナークラスを使用して画像をスキャンします。
ここにドキュメントがあります。
例として、Zbarスキャナークラスの使用方法、
ZBarImageScanner *scandoc = [[ZBarImageScanner alloc]init];
NSInteger resultsnumber = [scandoc scanImage:yourUIImage];
if(resultsnumber > 0){
ZBarSymbolSet *results = scandoc.results;
//Here you will get result.
}
以下のリンクが役立ちます。