DeepLearningで画像から判断してみよう #1
最近仕事で今表示されている画面から判断して自動で入力して、作業を行うことができないかという話が上がったので色々調べてみた。
今回はその第一弾として、まずは調べた結果をまとめておきます。
画面のスクショから何の画面か判断する
まずはこれです。今開いている画面のスクショを撮影し、何の画面が開いているかという判断をまず行う必要があります。
画像といえばOpenCVです。
最近はOpenCV3が出て、12月末にはOpenCV3.1がリリースされています。
OpenCV3になってからDeepLearningの機能が強化されたようです。
contlibとかって、ライブラリ機能が別で用意され自前で必要なものを用意するとか。。。
(まだこの辺はあまりよくわかってないです)
テンプレートを予め用意して、マッチングする箇所の座標を調べる方法としてTemplateMatchingという方法を取るようです。
Template Matching — OpenCV 2.4.12.0 documentation
画面のスクショとって、そのスクショの画像から場所を特定したいボタンだけを別画像でテンプレートとして用意してTemplateMatchingをやってみました。
for文で単純にX軸とY軸を少しずつ移動し、テンプレート画像と一致する場所を特定するという方法を取るわけですが、まぁ見事に場所は特定されるわけです。
けどボタンのサイズが変わったり画素数が変わるとうまくいくのかというと怪しい。。
ということは、テンプレート画像を縮小してみたり、ターゲット画像とテンプレート画像をグレースケール変換して比較してみたりといろいろ必要になります。
DeepLearningでやる前に読んでみたい記事
要はやりたいことってこれだなーと思った記事が以下。
※職場では少し開きづらい記事だなw
[Chainer] Deep Learning でアニメ (ゆるゆり) キャラクターを識別する(2015/11/4少し追記) | まさかり募集中
ChainerやGoogleが突然公開したTensorFlowを利用して学習させましょうということのようですね。
がしかし、学習用の画像を数千枚・・・
この方々は数千枚もの画像を用意したというのか・・・・
ワンパンマンが見たくて。。
今期アニメも最終回を無事次々と迎えてますね。
今期のアニメであったワンパンマン、調べてみると「となりのヤングジャンプ」というWEBサイトでマンガを無料公開しているではないですか。
(うまるのスピンオフもあるんだ・・・今知ったわ。。ザワザワ)
ただiPhoneで通勤中見ようと思ったら、レイアウト崩れが酷くて読めるレベルじゃない!
だったらSwiftで専用のビューアを作ってしまえ!ということで作りました↓
色々と本当はまだ手を加えるべきですが、AppStoreに公開するわけでもなく個人で楽しむ用なので一旦終了の意味も込めて今回やったことのメモ書きをしておきます。
環境
CocoaPods
Kanna
SVProgressHUD
SDWebImage
- これも言わずと知れた画像のライブラリ。
- 画像の読み込み時のスレッド処理を意識することなく書ける本当にいいライブラリ。
RealmSwift
- 最近使って見てるRealmさん。
- 前まではORマッパーのMagicalRecordを使ってましたが、最近はこっちの方が書き方が楽でいい。
- 今回は今までの冗長な書き方とは別の書き方でできたので、また勉強になった。
JOLImageSlider
- 画像のスライダーです。
- マンガ新刊情報でも使ったライブラリで、少しマンガ新刊情報用に拡張してるものを流用しました。
まとめ
これでおれのワンパンマンライフも快適だぜ!と思った矢先、公式の「となりのヤングジャンプ」さんは改修を行ったようで、正しくiPhoneで見れるようになってました。。。年末にお疲れ様です(いろんな意味で涙目)
Swift2.0で正規表現
Swiftで正規表現扱うときどうやるんだろうと思って調べてるうち行き着いた先が「EasyRamble」さんの以下の記事です。 http://easyramble.com/swift-regular-expression-utility.html
ただSwift2.0になって少し変わっているようなので、手を加えました。
init
変更前
init(_ pattern: String) { self.pattern = pattern var error: NSError? self.internalRegexp = NSRegularExpression( pattern: pattern, options: NSRegularExpressionOptions.CaseInsensitive, error: &error)! }
変更後
NSRegularExpression
の引数にエラーが含まれなくなったようです。
なので以下のようにtry catchへ変更しました。
init(_ pattern: String) { self.pattern = pattern do { self.internalRegexp = try NSRegularExpression(pattern: pattern, options: []) } catch let error as NSError { print(error.localizedDescription) self.internalRegexp = NSRegularExpression() } }
isMatch
変更前
func isMatch(input: String) -> Bool { let matches = self.internalRegexp.matchesInString( input, options: nil, range:NSMakeRange(0, count(input)) ) return matches.count > 0 }
変更後
optionsの指定方法ぐらいですね。
func isMatch(input: String) -> Bool { let nsString = input as NSString let matches = self.internalRegexp.matchesInString(input, options:[], range:NSMakeRange(0, nsString.length)) return matches.count > 0 }
matches
変更前
func matches(input: String) -> [String]? { if self.isMatch(input) { let matches = self.internalRegexp.matchesInString( input, options: nil, range:NSMakeRange(0, count(input)) ) var results: [String] = [] for i in 0 ..< matches.count { results.append( (input as NSString).substringWithRange(matches[i].range) ) } return results } return nil }
変更後
countの箇所でエラーが起きるので以下のように変更しています。
func matches(input: String) -> [String]? { if self.isMatch(input) { let nsString = input as NSString let matches = self.internalRegexp.matchesInString( input, options: [], range:NSMakeRange(0, nsString.length) ) var results: [String] = [] for i in 0 ..< matches.count { results.append( (input as NSString).substringWithRange(matches[i].range) ) } return results } return nil }
個人的に追加
正規表現で一致した内容を削るものです。
func delMatches(input:String) -> String { var strRet:String = "" if self.isMatch(input) { let matchList = self.matches(input) strRet = input for var i = 0; i < matchList!.count; i++ { strRet = strRet.stringByReplacingOccurrencesOfString(matchList![i], withString: "", options: [], range: nil) } } return strRet }
使い方
左側に正規表現を記載し、右側に対象の文字列を書きます。
Regexp("(\\d+)").delMatches(self._strTitle)
以上です。
LINEで送るをiOS9でやるには
起動時に出る謎のエラー
iOS9ではSchemeを使った実装方法が変わったらしいです。
XCode7にして、実機はiOS9に変更していろいろと触っていると、起動時によくわからないエラーが出ました。
先人の方々が言うにはplistでLSApplicationQueriesSchemes
を追加するように!とのこと。
これで謎のKindleエラーが消えました。
本題のLINEで送る
何も気にせずLINEで送るようのコードをSwiftで書いてたんですが、実際に動かしてみると・・・う、動かない。。。
@IBAction func pushLine(sender: AnyObject) { let text: String! = "Message!!" let encodeMessage: String! = text.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) let messageURL: NSURL! = NSURL( string: "line://msg/text/" + encodeMessage ) if (UIApplication.sharedApplication().canOpenURL(messageURL)) { UIApplication.sharedApplication().openURL( messageURL ) } }
Kindleと同じようにline
をLSApplicationQueriesSchemes
に追加してあげればいいんだな!
これでいけましたー!以上ですー。
Swiftで日付の操作
久しぶりの投稿です。
SwiftでCommonクラスに入れて使いまわしている日付取得用のメソッドです。
前はObjective−Cで書いていたのですが、Swiftに書き換えてみようと思い、土日数時間使ってちょこちょことやってます。
マンガ新刊情報〜圏外OK!買い忘れ防止アラートあり!〜
月を渡して表示させたい画像を選択
月の値を渡して画像を切り替えたいというときに使っています。
共通のメソッドは以下のようになってます。
/** 月から表示させる画像ファイル名を取得 */ func getMonthImage(strMonth:String)->String{ return commonConst.common.imageList[strMonth.toInt()!-1] }
画像のファイル名を月順に配列にもたせて、そこから取得する流れです。
class commonConst { struct common { static let imageList :[String] = [ "Jan.png", "Feb.png", "Mar.png", "Apr.png", "May.png", "Jun.png", "Jul.png", "Aug.png", "Sep.png", "Oct.png", "Nov.png", "Dec.png" ] } }
時差を取得
私が作ってる漫画の新刊情報取得アプリはローカルストレージに発売スケジュールを持ってます。
マンガの新刊情報ってそんな更新頻度ないんで1日1回だけ最新がないかチェックをかけてるわけです。
そういうわけで現在日時と前回更新日時の差分をとるためのメソッドです。
/** 時間の差分を取得 */ func diffDate(baseDate:NSDate,checkDate:NSDate) -> NSInteger{ var sinceInt = NSInteger(checkDate.timeIntervalSinceDate(baseDate)) return sinceInt/60 }
今日って第何週?
発売情報を週ごとに表示させる際、今日が第◯週だったらその週を最初から表示させてまう!
じゃ、今日は第何週目ですかー?というときのメソッドです。
(ULTRAMANかっこいい。。)
/** 今日が第何週か取得 */ func getTodayWeekOfMonth() -> Int { let calendar = NSCalendar.currentCalendar() var comp : NSDateComponents = calendar.components( NSCalendarUnit.CalendarUnitWeekOfMonth, fromDate: NSDate()) return comp.weekOfMonth }
日付フォーマット毎回書くの面倒
フォーマットさせたいNSDate型の日時と、取得したい日時フォーマット形式を渡すとStringで返してくれるメソッドです。
/** 日付のフォーマット */ func dateFormatter(date : NSDate, style : String) -> String { let dateFormatter = NSDateFormatter() dateFormatter.locale = NSLocale(localeIdentifier: "ja_JP") dateFormatter.dateFormat = style return dateFormatter.stringFromDate(date) }
使うときはこんな感じ。
/** 今日の月を取得 */ func getThisMonth()->String{ var now = dateFormatter(NSDate(), style: "M") return now }
以上ですー。
こうした方がかっこいいよ!というのがあればコメントよろしくですー。