Photos(写真).app上で選択中の写真が、指定場所から50メートル以内の場合にはファイルに書き出して、OCRアプリケーション「FineReader OCR Pro」でOCR処理するAppleScriptです。
–> Demo Movie
アーケードゲーム「戦場の絆」のリプレイムービーは、プレイ後の操作により1日に2プレイ分までYouTubeにアップロードされる仕様になっています。プレイ後、ゲーセンのターミナル上で操作してリプレイムービーにアクセスするためのアクセスコード(リプレイID)が表示されるようになっています。
この、ターミナル上のアクセスコードをiPhoneで写真撮影すると、写真に撮影場所のGPSデータが添付されます。写真.app経由でこのGPSデータを取得し、指定場所(ゲームセンター)から50メートル以内であればターミナルで撮影した写真と判定。
この写真をファイル書き出しして、OCRアプリケーションで認識しやすいようにCocoaの機能を用いて階調反転。一昔前ならPhotoshopで処理していましたが、いまならAppleScriptだけで高速に処理できます。デモムービーは実際の速度なので、その速さを体感していただけると思います。写真.appから選択中の写真を取得して反転するまで一瞬です。
反転した画像をMacのOCRアプリケーション「FineReader OCR Pro」でOCR処理し、YouTubeリプレイ再生用のコードを取得します。
あとは、再生用コードをリプレイムービー検索ページのフォームに入れて、実際のYouTube上のリプレイムービーのURLにアクセス。そのまま再生するなり、ダウンロードして保存しておくことになります。
■©創通・サンライズ
本サンプルでは、AppleScriptからコントロール可能なOCRアプリケーション「FineReader OCR Pro」を用いましたが、日本語の文字列を認識しないのであれば、Web APIのOCRサービス(MicrosoftのCognitive Serviceとか)を用いてみてもよいでしょう。
あとは、全国の「戦場の絆」が導入されているゲームセンターの住所情報および緯度経度情報がストックしてあるので、それらのGPSデータと写真撮影地点とのマッチングを行なってみてもよいかもしれません(700箇所程度なので、たいした演算ではありません)。
AppleScript名:Photosで選択中の写真が指定場所から50メートル以内の場合には書き出してFineReader OCR Proで処理 v2.1 |
— Created 2015-12-04 by Takaaki Naganoya –v2.1 — getDistanceBetweenTwoPlaces : Created 2015-03-03 by Shane Stanley — convAsFilteredJPEG : Created 2013-12-29 by badcharan@Twitter use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "CoreLocation" use framework "QuartzCore" property CIFilter : a reference to current application’s CIFilter property NSUUID : a reference to current application’s NSUUID property CIImage : a reference to current application’s CIImage property NSString : a reference to current application’s NSString property NSScanner : a reference to current application’s NSScanner property CLLocation : a reference to current application’s CLLocation property NSFileManager : a reference to current application’s NSFileManager property NSCharacterSet : a reference to current application’s NSCharacterSet property NSJPEGFileType : a reference to current application’s NSJPEGFileType property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep property NSMutableCharacterSet : a reference to current application’s NSMutableCharacterSet property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch set targPlace to {35.745769, 139.675565} –Game City Itabashi set bLoc to getSelectionOnPhotos() of me –Get Location From Photo set aDist to getDistanceBetweenTwoPlaces(targPlace, bLoc) of me –指定地点から50メートル以内の距離で撮影された写真であれば、Exportして後続の処理を行う if aDist is equal to false or aDist > 50 then return false –選択中の写真のうち最初のものだけExport set targPhotoAlias to exportSelectedPhotoOnPhotos() of me –実験に用いた写真はそのままではOCR処理できなかったので、手っ取り早く階調反転を行う set invertRes to convAsFilteredJPEG(targPhotoAlias, "CIColorInvert") of me if invertRes = false then display dialog "Error in CIImage" with title "Error" buttons {"OK"} default button 1 with icon 2 return end if set invImage to (POSIX file invertRes) as alias set outFileName to (NSUUID’s UUID()’s UUIDString() as text) & ".txt" set outPath to ((path to desktop) as text) & outFileName –sandbox環境ではパスは無視される tell application id "com.abbyy.FineReaderPro" activate –Check Ready set getReady to (is finereader controller active) if getReady = false then return –set idList to {English} –英語だとスペルチェックされて、"1"と"t"を誤認識するため英語の指定をやめた –Caution: this command is executed asynchronously –Caution: export command was changed in v12.1.4 set idList to {Basic, Java, Fortran, Cobol, Pascal} –認識ターゲット言語(C++の予約語はあるようだが、指定できないよ!) open invImage — In this version ,we have to open image, at first. export to txt outPath ocr languages enum idList retain layout (as plain text) encoding (utf8) –Wait for finish repeat 30 times set curStat to (is busy) if curStat = false then exit repeat delay 1 end repeat –sandbox環境(Mac App Store版)の場合にはファイル出力先を別途取得 set sandRes to (is sandboxed) if sandRes = true then set outDir to (get output dir) as text set outPath to (outDir & outFileName) as text end if end tell –OCR処理した結果のテキストを読み込む tell current application set textRes to read file outPath end tell –数字ではじまる行のみを抽出して、リプレイIDを取得 set textList to paragraphs of textRes set outList to {} repeat with i in textList set j to contents of i –1行あたりのテキストが8文字以上か? if length of j > 8 then –行頭の文字が数字か? set firstChar to first character of j set nRes to chkNumeric(firstChar) of me if nRes = true then set tmp1 to text 2 thru -1 of j –最初の数字を除去 –数字とアルファベット以外の文字を削除(タブ、スペースなど) set tmp2 to returnNumberAndAlphabetCharsOnly(tmp1) of me if length of tmp2 ≥ 8 then set tmp3 to text 1 thru 8 of tmp2 –数字とアルファベットの混在の文字列であれば出力する set tmp3Res to chkMixtureOfNumericAndAlphabet(tmp3) of me if tmp3Res = true then set the end of outList to tmp3 end if end if end if end if end repeat outList –> {"4f73vg1v", "v3v32zt3", "yk1z371x", "52yzvn11", "k1ftfvvg"}–Version 1.x (3rd ID is wrong) –> {"4f73vg1v", "v3v32zt3", "yk1z37tx", "52yzvn11", "k1ftfvvg"}– Version 2.0(Perfect!!!!) –> {"4f73vg1v", "v3v32zt3", "yk1z37tx", "52yzvn11", "k1ftfvvg"}– Version 2.1(Perfect!!!!) –> {"51n4gg1f", "2zxt41gg", "57k2txk9", "yy43f3gt", "4f73vg1v"} –Version 2.1(Perfect!!!!) –Photosで選択中の写真の1枚目(複数時には無視)から緯度、経度情報を取得する on getSelectionOnPhotos() tell application "Photos" set aa to selection if aa = {} or aa = missing value then return false set a to first item of aa set aProp to properties of a set aLoc to location of aProp return aLoc end tell end getSelectionOnPhotos –2点間の距離を計算する on getDistanceBetweenTwoPlaces(aPlaceLoc, bPlaceLoc) try set {aLat, aLong} to aPlaceLoc set {bLat, bLong} to bPlaceLoc on error return false end try set aPlace to CLLocation’s alloc()’s initWithLatitude:aLat longitude:aLong set bPlace to CLLocation’s alloc()’s initWithLatitude:bLat longitude:bLong set distanceInMetres to aPlace’s distanceFromLocation:bPlace return (distanceInMetres as real) end getDistanceBetweenTwoPlaces –Photos上で選択中の写真をTemporary Folderに掘ったフォルダに書き出して、そのalias情報を返す on exportSelectedPhotoOnPhotos() set dtPath to (path to temporary items) as text set aUUID to NSUUID’s UUID()’s UUIDString() as text set dirPath to ((POSIX path of dtPath) & aUUID) set fileManager to NSFileManager’s defaultManager() set aRes to (fileManager’s createDirectoryAtPath:dirPath withIntermediateDirectories:true attributes:(missing value) |error|:(reference)) set dtPath to dtPath & aUUID tell application "Photos" set a to selection if a = {} then return set aRes to (export a to file dtPath) end tell tell application "Finder" tell folder dtPath set fList to (every file) as alias list end tell end tell if fList = {} then return false return first item of fList end exportSelectedPhotoOnPhotos –CIFilterをかけたJPEG画像を生成 –参照:http://ashplanning.blogspot.jp/ のうちのどこか on convAsFilteredJPEG(aPath, aFilterName) –aliasをURL(input)とPOSIX path(output) に変換 set aURL to (current application’s |NSURL|’s fileURLWithPath:(POSIX path of aPath)) –Input set aPOSIX to (POSIX path of aPath) & "_" & aFilterName & ".jpg" –Output –CIImageを生成 set aCIImage to CIImage’s alloc()’s initWithContentsOfURL:aURL — CIFilter をフィルタの名前で生成 set aFilter to CIFilter’s filterWithName:aFilterName aFilter’s setDefaults() –各フィルタのパラメータはデフォルト –Filterを実行 aFilter’s setValue:aCIImage forKey:"inputImage" set aOutImage to aFilter’s valueForKey:"outputImage" — NSBitmapImageRep を CIImage から生成 set aRep to NSBitmapImageRep’s alloc()’s initWithCIImage:aOutImage — NSBitmapImageRep から JPEG データを取得 set jpegData to aRep’s representationUsingType:(NSJPEGFileType) |properties|:(missing value) — ファイルに保存 set fsRes to jpegData’s writeToFile:aPOSIX atomically:true if (fsRes as boolean) = false then return false –失敗した場合 return aPOSIX –成功した場合 end convAsFilteredJPEG –数字とアルファベットの混在状態の時にtrueを返す on chkMixtureOfNumericAndAlphabet(checkString) set a0Res to chkAlphabetAndNumeric(checkString) of me set a1Res to chkNumeric(checkString) of me set a2Res to chkAlphabet(checkString) of me if {a0Res, a1Res, a2Res} = {true, false, false} then return true else return false end if end chkMixtureOfNumericAndAlphabet –数字のみかを調べて返す on chkNumeric(checkString) set digitCharSet to NSCharacterSet’s characterSetWithCharactersInString:"0123456789" set ret to my chkCompareString:checkString baseString:digitCharSet return ret as boolean end chkNumeric — アルファベットのみか調べて返す on chkAlphabet(checkString) set aStr to NSString’s stringWithString:checkString set allCharSet to NSMutableCharacterSet’s alloc()’s init() allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "a", 26)) allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "A", 26)) set aBool to my chkCompareString:aStr baseString:allCharSet return aBool as boolean end chkAlphabet — アルファベットと数字のみか調べて返す on chkAlphabetAndNumeric(checkString) set aStr to NSString’s stringWithString:checkString set allCharSet to NSMutableCharacterSet’s alloc()’s init() allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "0", 10)) allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "a", 26)) allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "A", 26)) set aBool to my chkCompareString:aStr baseString:allCharSet return aBool as boolean end chkAlphabetAndNumeric on chkCompareString:checkString baseString:baseString set aScanner to NSScanner’s localizedScannerWithString:checkString aScanner’s setCharactersToBeSkipped:(missing value) aScanner’s scanCharactersFromSet:baseString intoString:(missing value) return (aScanner’s isAtEnd()) as boolean end chkCompareString:baseString: –文字置換 on repChar(aStr, targStr, repStr) set aString to NSString’s stringWithString:aStr set bString to aString’s stringByReplacingOccurrencesOfString:targStr withString:repStr return bString as text end repChar –アルファベットと数字以外を削除して返す on returnNumberAndAlphabetCharsOnly(aStr) set anNSString to NSString’s stringWithString:aStr set anNSString to anNSString’s stringByReplacingOccurrencesOfString:"[^0-9A-Za-z]" withString:"" options:(NSRegularExpressionSearch) range:{0, anNSString’s |length|()} return anNSString as text end returnNumberAndAlphabetCharsOnly |