ピッカーで選択した画像をリサイズして表示する
1. OpenCVの準備をする
2. Bridge header.hの修正 (以下を追加)
#import "OpenCVWrapper.h" // 追加
3. OpenCvWrapper.h の修正
(作成する関数を記載する)
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface OpenCvWrapper : NSObject
// funciton to get opencv version
+(NSString * ) openCVVersionString;
+(UIImage * ) openCvResize:(UIImage * )image targetWidth:(int)width targetHeight:(int)height;
@end
4. C++コードを OpenCvWrapper.mm に記載する
#import <opencv2/opencv.hpp> // 追加
// #import <opencv2/highgui.hpp>
#import <opencv2/imgcodecs/ios.h> // UIImageToMatなどに必要(3.1.1以降はコレの模様)
#import "OpenCvWrapper.h"
@implementation OpenCvWrapper // swiftからはこのクラス名でアクセス
// 追加関数 ()
+(NSString *) openCVVersionString
{
return [NSString stringWithFormat: @"openCV Version %s", CV_VERSION];
}
// 引数x3を受けてUIImageを返す関数(param2,3はラベルをつけるらしい)
// 呼び出し側(Swift)はこんな感じに
// OpenCvWrapper.openCvResize(image, targetWidth: 320, targetHeight: 240)
+(UIImage*) openCvResize:(UIImage * )image targetWidth:(int)width targetHeight:(int)height
{
// UIImage uiImag2
NSLog(@"width:%d height:%d", width, height);
if(width > height) {
// 横画像
NSLog(@"横画像");
} else {
// 縦画像
NSLog(@"縦画像");
}
cv::Mat imageMat;
UIImageToMat(image, imageMat);
cv::Mat resizedMat(cv::Size(width, height), imageMat.type());
cv::resize(imageMat, resizedMat, resizedMat.size(), cv::INTER_LINEAR);
// cv::Mat resizedMat(cv::Size(10, 10), CV_8UC3, cv::Scalar(0,0,255));
return MatToUIImage(resizedMat);
}
@end
5. ViewController.swiftに上記の関数を呼び出すコードを記載する
// 本アプリは以下の動作をします
// 1. ImageViewをタップするとpicker controllerが表示
// 2. picker controllerで写真を選択するとImgeViwに写真を表示
import UIKit
class ViewController: UIViewController , UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var imagePicker: UIImagePickerController!
@IBOutlet weak var photoView: UIImageView!
let tagPhotoView = 1
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// viewにタグを設定(本筋ではないがImageViewをタッチした際にpicker controllerを表示させるため)
photoView.tag = tagPhotoView
// インスタンス生成
imagePicker = UIImagePickerController()
// デリゲート設定
imagePicker.delegate = self
// 画像の取得先はフォトライブラリとする(カメラにするとカメラを起動した撮影した画像を取得できるみたい)
// この段階ではImagePickerは起動させません(エラーになるから...)
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
// self.presentViewController(imagePicker, animated: true, completion: nil)
}
override func viewDidAppear(animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// ImagePickerControllerで画像を選択した際に呼び出されるdelegate (self指定の為)
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
// Add your functionality here
//選択された画像を取得.
let selectedImage: AnyObject? = info[UIImagePickerControllerOriginalImage]
//選択された画像を表示するViewContorllerにセットする.
let image = (selectedImage as! UIImage)
// photoView.image = (selectedImage as! UIImage)
print("\(image.size.width) x \(image.size.height) : \(photoView.layer.bounds.width) x \(photoView.layer.bounds.height)")
// リサイズ
let resizedImage = OpenCvWrapper.openCvResize(image, targetWidth: 160, targetHeight: 160)
// let resizedImage = OpenCvWrapper.openCvResize(image, targetWidth: Int32(photoView.layer.bounds.width), targetHeight: Int32(photoView.layer.bounds.height))
// viewControllerに設定
photoView.image = resizedImage
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
}
// 画像選択がキャンセルされた時に呼ばれる.
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
}
// user interaction enable / multiple touchをチェックしておく
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
for touch: UITouch in touches {
let tag = touch.view!.tag
switch tag {
case tagPhotoView:
self.presentViewController(imagePicker, animated: true, completion: nil)
default:
break
}
}
}
}
※ ImagePickerのサンプル で、取得した画像をリサイスするように修正したコードです
http://tantan2014.blogspot.jp/2017/10/uiimagepickercontroller.html
2017年11月1日水曜日
2017年10月30日月曜日
アルバムから写真を取得して表示する(UIImagePickerController)
UIImagePickerControllerを使って写真を取得してUIImageViewに表示します。
動作としては、
1. ImageViewをタップするとpicker controllerが表示
2. picker controllerで写真を選択するとImgeViewに写真を表示
となります。
1. info.plistに "Privacy - Photo Library Usage Description"を追加して、Valueにメッセージ("アルバムにアクセスします"とか)を記載します。
2. MainStoryBoardにImaveViewを配置しますし、ViewControllerにIBOutlet接続します。
@IBOutlet weak var photoView: UIImageView! とか
3. ViewControllerクラスの継承元に以下を追加する
UIImagePickerControllerDelegate,
UINavigationControllerDelegate
こんな感じになる↓
class ViewController: UIViewController , UIImagePickerControllerDelegate, UINavigationControllerDelegate
4. クラスメンバに変数追加
var imagePicker: UIImagePickerController!
let tagPhotoView = 1
5. ViewDidLoadedに以下の処理を記載 (ViewDidLoadedでimagepickerControllerを起動させようとするとエラーが出るのでやってないというか)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// viewにタグを設定(本筋ではないがImageViewをタッチした際にpicker controllerを表示させるため)
photoView.tag = tagPhotoView
// インスタンス生成
imagePicker = UIImagePickerController()
// デリゲート設定
imagePicker.delegate = self
// 画像の取得先はフォトライブラリとする(カメラにするとカメラを起動した撮影した画像を取得できるみたい)
// この段階ではImagePickerは起動させません
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
// self.presentViewController(imagePicker, animated: true, completion: nil)
}
4. ViewControllerがタップされたらImagePicker controllerを起動するコード
/*
user interaction enable / multiple touchをチェックしておく
*/
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
for touch: UITouch in touches {
let tag = touch.view!.tag
switch tag {
case tagPhotoView:
self.presentViewController(imagePicker, animated: true, completion: nil)
default:
// self.presentViewController(imagePicker, animated: true, completion: nil)
break
}
}
}
5. imagePickerControllerで画面が選択されたら呼ばれる関数を記述
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
// Add your functionality here
//選択された画像を取得.
let selectedImage: AnyObject? = info[UIImagePickerControllerOriginalImage]
//選択された画像を表示するViewContorllerにセットする.
photoView.image = (selectedImage as! UIImage)
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
// ステータスバーの非表示 (ただし、時計表示などは消えないみたい)
// self.setNeedsStatusBarAppearanceUpdate()
}
// 画像選択がキャンセルされた時に呼ばれる.
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
}
とりあえず上記実装で意図した動作はするようです。
ソースコード全体
// 本アプリは以下の動作をします
// 1. ImageViewをタップするとpicker controllerが表示
// 2. picker controllerで写真を選択するとImgeViwに写真を表示
import UIKit
class ViewController: UIViewController , UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var imagePicker: UIImagePickerController!
@IBOutlet weak var photoView: UIImageView!
let tagPhotoView = 1
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// viewにタグを設定(本筋ではないがImageViewをタッチした際にpicker controllerを表示させるため)
photoView.tag = tagPhotoView
// インスタンス生成
imagePicker = UIImagePickerController()
// デリゲート設定
imagePicker.delegate = self
// 画像の取得先はフォトライブラリとする(カメラにするとカメラを起動した撮影した画像を取得できるみたい)
// この段階ではImagePickerは起動させません(エラーになるから...)
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(imagePicker, animated: true, completion: nil)
}
override func viewDidAppear(animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
// Add your functionality here
//選択された画像を取得.
let selectedImage: AnyObject? = info[UIImagePickerControllerOriginalImage]
//選択された画像を表示するViewContorllerにセットする.
photoView.image = (selectedImage as! UIImage)
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
}
// 画像選択がキャンセルされた時に呼ばれる.
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
}
// user interaction enable / multiple touchをチェックしておく
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
for touch: UITouch in touches {
let tag = touch.view!.tag
switch tag {
case tagPhotoView:
self.presentViewController(imagePicker, animated: true, completion: nil)
default:
break
}
}
}
}
覚書...
ViewDidLoadedでimage picker controllerを起動させた時に表示されるエラーメッセージ
PhotoViewer01[27898:560863] Warning: Attempt to present <UIImagePickerController: 0x7fcd3300f600> on <PhotoViewer01.ViewController: 0x7fcd32622b10> whose view is not in the window hierarchy!
動作としては、
1. ImageViewをタップするとpicker controllerが表示
2. picker controllerで写真を選択するとImgeViewに写真を表示
となります。
1. info.plistに "Privacy - Photo Library Usage Description"を追加して、Valueにメッセージ("アルバムにアクセスします"とか)を記載します。
2. MainStoryBoardにImaveViewを配置しますし、ViewControllerにIBOutlet接続します。
@IBOutlet weak var photoView: UIImageView! とか
3. ViewControllerクラスの継承元に以下を追加する
UIImagePickerControllerDelegate,
UINavigationControllerDelegate
こんな感じになる↓
class ViewController: UIViewController , UIImagePickerControllerDelegate, UINavigationControllerDelegate
4. クラスメンバに変数追加
var imagePicker: UIImagePickerController!
let tagPhotoView = 1
5. ViewDidLoadedに以下の処理を記載 (ViewDidLoadedでimagepickerControllerを起動させようとするとエラーが出るのでやってないというか)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// viewにタグを設定(本筋ではないがImageViewをタッチした際にpicker controllerを表示させるため)
photoView.tag = tagPhotoView
// インスタンス生成
imagePicker = UIImagePickerController()
// デリゲート設定
imagePicker.delegate = self
// 画像の取得先はフォトライブラリとする(カメラにするとカメラを起動した撮影した画像を取得できるみたい)
// この段階ではImagePickerは起動させません
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
// self.presentViewController(imagePicker, animated: true, completion: nil)
}
4. ViewControllerがタップされたらImagePicker controllerを起動するコード
/*
user interaction enable / multiple touchをチェックしておく
*/
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
for touch: UITouch in touches {
let tag = touch.view!.tag
switch tag {
case tagPhotoView:
self.presentViewController(imagePicker, animated: true, completion: nil)
default:
// self.presentViewController(imagePicker, animated: true, completion: nil)
break
}
}
}
5. imagePickerControllerで画面が選択されたら呼ばれる関数を記述
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
// Add your functionality here
//選択された画像を取得.
let selectedImage: AnyObject? = info[UIImagePickerControllerOriginalImage]
//選択された画像を表示するViewContorllerにセットする.
photoView.image = (selectedImage as! UIImage)
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
// ステータスバーの非表示 (ただし、時計表示などは消えないみたい)
// self.setNeedsStatusBarAppearanceUpdate()
}
// 画像選択がキャンセルされた時に呼ばれる.
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
}
とりあえず上記実装で意図した動作はするようです。
ソースコード全体
// 本アプリは以下の動作をします
// 1. ImageViewをタップするとpicker controllerが表示
// 2. picker controllerで写真を選択するとImgeViwに写真を表示
import UIKit
class ViewController: UIViewController , UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var imagePicker: UIImagePickerController!
@IBOutlet weak var photoView: UIImageView!
let tagPhotoView = 1
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// viewにタグを設定(本筋ではないがImageViewをタッチした際にpicker controllerを表示させるため)
photoView.tag = tagPhotoView
// インスタンス生成
imagePicker = UIImagePickerController()
// デリゲート設定
imagePicker.delegate = self
// 画像の取得先はフォトライブラリとする(カメラにするとカメラを起動した撮影した画像を取得できるみたい)
// この段階ではImagePickerは起動させません(エラーになるから...)
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(imagePicker, animated: true, completion: nil)
}
override func viewDidAppear(animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
// Add your functionality here
//選択された画像を取得.
let selectedImage: AnyObject? = info[UIImagePickerControllerOriginalImage]
//選択された画像を表示するViewContorllerにセットする.
photoView.image = (selectedImage as! UIImage)
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
}
// 画像選択がキャンセルされた時に呼ばれる.
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
// モーダルビューを閉じる
self.dismissViewControllerAnimated(true, completion: nil)
}
// user interaction enable / multiple touchをチェックしておく
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
for touch: UITouch in touches {
let tag = touch.view!.tag
switch tag {
case tagPhotoView:
self.presentViewController(imagePicker, animated: true, completion: nil)
default:
break
}
}
}
}
覚書...
ViewDidLoadedでimage picker controllerを起動させた時に表示されるエラーメッセージ
PhotoViewer01[27898:560863] Warning: Attempt to present <UIImagePickerController: 0x7fcd3300f600> on <PhotoViewer01.ViewController: 0x7fcd32622b10> whose view is not in the window hierarchy!
2017年10月29日日曜日
iOSのstataus barを非表示にする
Swiftでアプリを生成した場合にstatus barを表示させない手続きについて記載します。
1. Porjectを選択して General -> Deployment Infoにある"Hide Status Bar"をチェックする
2. info.plistで適当な箇所で+ -> "Status bar is infinity hidden" を追加 -> Valueを"NO"にする
info.plistの "Status bar is infinity hidden"が"YES"にする必要もあるようですが、"1"の手順で追加・設定されるようです( ということで、今回の手順でも触っていません)
ということで、この状態でbuldしてstatus barの表示されないアプリになっている事が確認できました。
1. Porjectを選択して General -> Deployment Infoにある"Hide Status Bar"をチェックする
2. info.plistで適当な箇所で+ -> "Status bar is infinity hidden" を追加 -> Valueを"NO"にする
info.plistの "Status bar is infinity hidden"が"YES"にする必要もあるようですが、"1"の手順で追加・設定されるようです( ということで、今回の手順でも触っていません)
ということで、この状態でbuldしてstatus barの表示されないアプリになっている事が確認できました。
2017年10月23日月曜日
SwiftでOpenCV...の準備
iOSでOpenCVを動かしてみようと思いましたが結構難航してます。
cocoapodsでパッケージを取得する方法が簡単そうだったのですが一部のファイルが入らないようで諦めました。
iOS packをプロジェクトに手動で追加する方法でビルドと(emulatorでの)OpenCVのversion表示ができたのでここまでを記載してみます
1. 以下からiOS packをダウンロードする
https://opencv.org/releases.html
2. 解凍してできたフォルダ"opencv2.framework"をフォルダごとworkspaceにドラッグ&ドロップする。ダイアログが表示されたら”Copy items if needed”をチェックする ( workspace に”opencv2.framework”が配置され、最初は×が表示されているがその後に消える)
3. C++を書くために、File -> New -> File -> “Cocoa Touch Class”を選択。言語はObjective-Cとする (名前は”OpenCvWrapper”などとしておく...以下はOpenCvWrapperとした時の例です)
4. dialogがpop upして、objective-Cのbridge wrapperを作るか聞かれるので”Create Bridge Header”を選択する
5. bridge header “*.m”が生成されるが、*.mmにファイル名を変更する (objective-Cのheaderはこうなのか??)
6. OpenCvWrappter.hを以下に変更
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface OpenCvWrapper : NSObject
// funciton to get opencv version
+(NSString * ) openCVVersionString;
@end
7. プロジェクト名-bridging-header.hを以下に変更
#import "OpenCVWrapper.h" // 追加
8. OpenCvWrappter.mmにC++のコードを書く (下記はversionを表示するwrapperのコード)
// 本ファイルはOpenCvWrappter.m だったので、OpenCvWrappter.mm にファイル名を変更した
// 本ファイルはOpenCvWrappter.m だったので、OpenCvWrappter.m にファイル名を変更した。"Expected identifier"が出る場合(NOのenum関連)、importの順序を以下の順にする(逆で発生していた。opencv2のheaderの読み込みを標準のheaderより前に持ってくる事で解消)
#import <opencv2/opencv.hpp> // 追加
#import "OpenCvWrapper.h"
@implementation OpenCvWrapper
// 追加関数 ()
+(NSString *) openCVVersionString
{
return [NSString stringWithFormat: @"openCV Version %s", CV_VERSION];
}
@end
9. Swift側にコードを記載する (以下は、labelにversionを表示する場合。UIはlabelの配置のみ)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// versionを表示してみる
versionLabel.text = OpenCvWrapper.openCVVersionString() // wrapper関数の呼び出し
}
ちょっとややこしいが
- **bridge-header.h : 本ファイルでimportしているheader fileに描かれているクラスなどをswift側から使用することができる
- **.h : **.mm (C++ソースファイル)のheaderファイル。
- **.mm : C++ソースファイル。ビルド時に”Expected identifier”が表示される場合はsystemとOpenCVのimportの順を逆にしてみる(OpenCVを先、systemを後にすると回避できた)
こちらのページを参考にさせていただきました
https://blog.fenrir-inc.com/jp/2017/04/opencv-3-2-in-a-swift-project.html
http://o-tyazuke.hatenablog.com/entry/2016/11/27/164908
cocoapodsでパッケージを取得する方法が簡単そうだったのですが一部のファイルが入らないようで諦めました。
iOS packをプロジェクトに手動で追加する方法でビルドと(emulatorでの)OpenCVのversion表示ができたのでここまでを記載してみます
1. 以下からiOS packをダウンロードする
https://opencv.org/releases.html
2. 解凍してできたフォルダ"opencv2.framework"をフォルダごとworkspaceにドラッグ&ドロップする。ダイアログが表示されたら”Copy items if needed”をチェックする ( workspace に”opencv2.framework”が配置され、最初は×が表示されているがその後に消える)
3. C++を書くために、File -> New -> File -> “Cocoa Touch Class”を選択。言語はObjective-Cとする (名前は”OpenCvWrapper”などとしておく...以下はOpenCvWrapperとした時の例です)
4. dialogがpop upして、objective-Cのbridge wrapperを作るか聞かれるので”Create Bridge Header”を選択する
5. bridge header “*.m”が生成されるが、*.mmにファイル名を変更する (objective-Cのheaderはこうなのか??)
6. OpenCvWrappter.hを以下に変更
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface OpenCvWrapper : NSObject
// funciton to get opencv version
+(NSString * ) openCVVersionString;
@end
7. プロジェクト名-bridging-header.hを以下に変更
#import "OpenCVWrapper.h" // 追加
8. OpenCvWrappter.mmにC++のコードを書く (下記はversionを表示するwrapperのコード)
// 本ファイルはOpenCvWrappter.m だったので、OpenCvWrappter.mm にファイル名を変更した
// 本ファイルはOpenCvWrappter.m だったので、OpenCvWrappter.m にファイル名を変更した。"Expected identifier"が出る場合(NOのenum関連)、importの順序を以下の順にする(逆で発生していた。opencv2のheaderの読み込みを標準のheaderより前に持ってくる事で解消)
#import <opencv2/opencv.hpp> // 追加
#import "OpenCvWrapper.h"
@implementation OpenCvWrapper
// 追加関数 ()
+(NSString *) openCVVersionString
{
return [NSString stringWithFormat: @"openCV Version %s", CV_VERSION];
}
@end
9. Swift側にコードを記載する (以下は、labelにversionを表示する場合。UIはlabelの配置のみ)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// versionを表示してみる
versionLabel.text = OpenCvWrapper.openCVVersionString() // wrapper関数の呼び出し
}
ちょっとややこしいが
- **bridge-header.h : 本ファイルでimportしているheader fileに描かれているクラスなどをswift側から使用することができる
- **.h : **.mm (C++ソースファイル)のheaderファイル。
- **.mm : C++ソースファイル。ビルド時に”Expected identifier”が表示される場合はsystemとOpenCVのimportの順を逆にしてみる(OpenCVを先、systemを後にすると回避できた)
こちらのページを参考にさせていただきました
https://blog.fenrir-inc.com/jp/2017/04/opencv-3-2-in-a-swift-project.html
http://o-tyazuke.hatenablog.com/entry/2016/11/27/164908
2017年10月20日金曜日
bluetoothキーボードとマウスが不安定
Windows10を使用していますが、bluetooth keyboard / mouseがよく切断されて非常に使いづらい感じになっていました。
私の場合はbluetoothドライバの電源設定を変更したら切断されなくなり快適になりました..等と書いていたら途中ひっかかりましたがすぐに復元しました。
vaioのページが参考になりました。
https://solutions.vaio.com/2706#s7
私の場合はbluetoothドライバの電源設定を変更したら切断されなくなり快適になりました..等と書いていたら途中ひっかかりましたがすぐに復元しました。
vaioのページが参考になりました。
https://solutions.vaio.com/2706#s7
2017年10月19日木曜日
tesseract-ocrとC#で7セグを読み取ってみる
OCRで検索するとよく見かけるのが本題のtesseract-ocrでしたのでこちらを使ってみました。
C#で使ってみたかったのでNuGetで導入してみます。
"Tesseract"で検索するといくつか見つかるのですが、Charles Weldさんのパッケージがよく使われているようです(文言は若干異なるようですが...)
言語データは別途ダウンロード & 配置するのですが、今回は7セグ用の学習データを使わせてもらいます。
https://github.com/arturaugusto/display_ocr
こちらをダウンロードします。
学習データのフォルダ構成の中で、以下が学習データっぽく、この階層のファイルを指定すれば良さそうですが...
display_ocr-master\letsgodigital\letsgodigital.traineddata
他の言語などを見ると言語(上記で言うと"letsgodigital"の下に"tessdata"の下に上記ファイルが配置されているようですので、"tessdata"というフォルダを掘ってその下に上記階層のファイルを配置しました(この辺のしきたりはよく解っていません)。
また、VisualStudioのprojectフォルダはパスにspaceが入っていたりするので、ユーザーフォルダに配置しています(なるべくトラブらないようにしているだけで実は問題ないかもしれません)。
ということで学習データのパスは以下としています。
C:\Users\hoge\Documents\tmp\display_ocr-master\letsgodigital\tessdata
コードは以下ですが文字によっては認識してくれるようです。
サンプル画像はgoogleの画像検索で7セグの画像を探してきたのですが...
- 白地に黒文字
- セグメントがつながっている方が認識しやすかった(学習データの中の画像はseg毎に分離しているのでつながっていない画像で学習していると思うのですが...)
- 文字が画像の端まであると認識してくれない (要余白?)
という感じで、誤認識やそもそも読めない場合もあるようです。
(文字列の部分に\nだけ表示されたりするようです...以下のコードで読める画像もあればNGなのもあるようです)
コードは以下で動かしてみました。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Tesseract; // 追加
using System.Diagnostics;
namespace tesseract01
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// 解析したい画像のファイルパス
var imgPath = @"C:\Users\hoge\Documents\tmp\7seg8.png";
// jpn.traineddata等の学習データが格納されたディレクトリパス
var dataDirPath = @"C:\Users\hoge\Documents\tmp\display_ocr-master\letsgodigital";
// 使用する学習データの言語(ディレクトリパスに格納されている言語に限る)
var lang = "letsgodigital";
if (!System.IO.File.Exists(imgPath))
{
Console.Error.WriteLine("画像のパスに画像が見つかりませんでした");
return;
}
string traindedDataPath = System.IO.Path.Combine(dataDirPath, "tessdata", lang + ".traineddata");
if (!System.IO.File.Exists(traindedDataPath))
{
Console.Error.WriteLine(lang + ".traineddataがみつかりませんでした");
return;
}
using (var image = new System.Drawing.Bitmap(imgPath))
{
try {
using (var engine = new Tesseract.TesseractEngine(dataDirPath, lang))
{
engine.DefaultPageSegMode = PageSegMode.SingleLine;
using (var page = engine.Process(image))
{
var resultText = page.GetText();
Console.Write(resultText);
}
}
} catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
}
}
参考にさせていただきましたページ
http://whoopsidaisies.hatenablog.com/entry/2013/12/16/174819
http://blog.nomulabo.com/article/422712502.html
http://blog.ch3cooh.jp/entry/20140718/1405643400
C#で使ってみたかったのでNuGetで導入してみます。
"Tesseract"で検索するといくつか見つかるのですが、Charles Weldさんのパッケージがよく使われているようです(文言は若干異なるようですが...)
言語データは別途ダウンロード & 配置するのですが、今回は7セグ用の学習データを使わせてもらいます。
https://github.com/arturaugusto/display_ocr
こちらをダウンロードします。
学習データのフォルダ構成の中で、以下が学習データっぽく、この階層のファイルを指定すれば良さそうですが...
display_ocr-master\letsgodigital\letsgodigital.traineddata
他の言語などを見ると言語(上記で言うと"letsgodigital"の下に"tessdata"の下に上記ファイルが配置されているようですので、"tessdata"というフォルダを掘ってその下に上記階層のファイルを配置しました(この辺のしきたりはよく解っていません)。
また、VisualStudioのprojectフォルダはパスにspaceが入っていたりするので、ユーザーフォルダに配置しています(なるべくトラブらないようにしているだけで実は問題ないかもしれません)。
ということで学習データのパスは以下としています。
C:\Users\hoge\Documents\tmp\display_ocr-master\letsgodigital\tessdata
コードは以下ですが文字によっては認識してくれるようです。
サンプル画像はgoogleの画像検索で7セグの画像を探してきたのですが...
- 白地に黒文字
- セグメントがつながっている方が認識しやすかった(学習データの中の画像はseg毎に分離しているのでつながっていない画像で学習していると思うのですが...)
- 文字が画像の端まであると認識してくれない (要余白?)
という感じで、誤認識やそもそも読めない場合もあるようです。
(文字列の部分に\nだけ表示されたりするようです...以下のコードで読める画像もあればNGなのもあるようです)
コードは以下で動かしてみました。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Tesseract; // 追加
using System.Diagnostics;
namespace tesseract01
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// 解析したい画像のファイルパス
var imgPath = @"C:\Users\hoge\Documents\tmp\7seg8.png";
// jpn.traineddata等の学習データが格納されたディレクトリパス
var dataDirPath = @"C:\Users\hoge\Documents\tmp\display_ocr-master\letsgodigital";
// 使用する学習データの言語(ディレクトリパスに格納されている言語に限る)
var lang = "letsgodigital";
if (!System.IO.File.Exists(imgPath))
{
Console.Error.WriteLine("画像のパスに画像が見つかりませんでした");
return;
}
string traindedDataPath = System.IO.Path.Combine(dataDirPath, "tessdata", lang + ".traineddata");
if (!System.IO.File.Exists(traindedDataPath))
{
Console.Error.WriteLine(lang + ".traineddataがみつかりませんでした");
return;
}
using (var image = new System.Drawing.Bitmap(imgPath))
{
try {
using (var engine = new Tesseract.TesseractEngine(dataDirPath, lang))
{
engine.DefaultPageSegMode = PageSegMode.SingleLine;
using (var page = engine.Process(image))
{
var resultText = page.GetText();
Console.Write(resultText);
}
}
} catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
}
}
参考にさせていただきましたページ
http://whoopsidaisies.hatenablog.com/entry/2013/12/16/174819
http://blog.nomulabo.com/article/422712502.html
http://blog.ch3cooh.jp/entry/20140718/1405643400
2017年10月18日水曜日
リサイズした画像をcv2.imwriteで保存してみる
以下の手直しを実施
- アスペクトを整える
- リサイズ後のサイズを表示する : textbox4
- 保存ボタン押下で画像をcurrent directoryに保存
- stop watchによる処理時間の目安をdebug出力に表示
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO; // file / directory文字列処理など
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System.Diagnostics;
namespace DragDrop01
{
public partial class Form1 : Form
{
Mat resizedImage;
public Form1()
{
InitializeComponent();
listBox1.AllowDrop = true; // プロパティを編集してもよい(やらないとEnterイベントが発生しない模様)
resizedImage = new Mat();
}
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
} else
{
e.Effect = DragDropEffects.None;
}
}
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
string[] fileName = (string[])e.Data.GetData(DataFormats.FileDrop, false);
listBox1.Items.AddRange(fileName);
}
// listboxの選択変更
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string currentItem = listBox1.SelectedItem.ToString(); // アイテムを取得する
// int index = listBox1.FindString(currentItem); // (↑のアイテムから)indexを取得する事も可
textBox1.Text = Path.GetDirectoryName(currentItem);
textBox2.Text = Path.GetFileName(currentItem);
Mat image = new Mat(currentItem);
string imageSize = image.Width.ToString() + " : " + image.Height.ToString();
textBox3.Text = imageSize.ToString();
int targetHeight = image.Height * pictureBox1.Width / image.Width;
textBox4.Text = pictureBox1.Width.ToString() + " : " + targetHeight.ToString();
Stopwatch sw = new Stopwatch();
sw.Start();
Cv2.Resize(image, resizedImage, new OpenCvSharp.Size(pictureBox1.Width, targetHeight));
Debug.WriteLine(sw.Elapsed);
pictureBox1.Image = BitmapConverter.ToBitmap(resizedImage);
Debug.WriteLine(sw.Elapsed);
sw.Stop();
}
// 保存ボタン押下処理
private void button_save_Click(object sender, EventArgs e)
{
// 実行ファイルのcurrent dirに保存してみる
string currentDir = Directory.GetCurrentDirectory() + "\\" + textBox2.Text;
Cv2.ImWrite(currentDir, resizedImage);
}
}
}
- アスペクトを整える
- リサイズ後のサイズを表示する : textbox4
- 保存ボタン押下で画像をcurrent directoryに保存
- stop watchによる処理時間の目安をdebug出力に表示
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO; // file / directory文字列処理など
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System.Diagnostics;
namespace DragDrop01
{
public partial class Form1 : Form
{
Mat resizedImage;
public Form1()
{
InitializeComponent();
listBox1.AllowDrop = true; // プロパティを編集してもよい(やらないとEnterイベントが発生しない模様)
resizedImage = new Mat();
}
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
} else
{
e.Effect = DragDropEffects.None;
}
}
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
string[] fileName = (string[])e.Data.GetData(DataFormats.FileDrop, false);
listBox1.Items.AddRange(fileName);
}
// listboxの選択変更
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string currentItem = listBox1.SelectedItem.ToString(); // アイテムを取得する
// int index = listBox1.FindString(currentItem); // (↑のアイテムから)indexを取得する事も可
textBox1.Text = Path.GetDirectoryName(currentItem);
textBox2.Text = Path.GetFileName(currentItem);
Mat image = new Mat(currentItem);
string imageSize = image.Width.ToString() + " : " + image.Height.ToString();
textBox3.Text = imageSize.ToString();
int targetHeight = image.Height * pictureBox1.Width / image.Width;
textBox4.Text = pictureBox1.Width.ToString() + " : " + targetHeight.ToString();
Stopwatch sw = new Stopwatch();
sw.Start();
Cv2.Resize(image, resizedImage, new OpenCvSharp.Size(pictureBox1.Width, targetHeight));
Debug.WriteLine(sw.Elapsed);
pictureBox1.Image = BitmapConverter.ToBitmap(resizedImage);
Debug.WriteLine(sw.Elapsed);
sw.Stop();
}
// 保存ボタン押下処理
private void button_save_Click(object sender, EventArgs e)
{
// 実行ファイルのcurrent dirに保存してみる
string currentDir = Directory.GetCurrentDirectory() + "\\" + textBox2.Text;
Cv2.ImWrite(currentDir, resizedImage);
}
}
}
2017年10月17日火曜日
drag and dropとLixt Box
Listboxにドラッグ & ドロップしたファイルを表示してみます。
以下をformに配置します。
picturebox : 画像表示用
textbox x 3 : ディレクトリ名表示・ファイル名表示・画像サイズ表示 (表示するだけなのでlabelでも可です)
listbox : ドラッグ & ドロップはこちらに対して行います
listboxにファイルをドラッグ & ドロップするとアイテムが増え、listboxのアイテムを選択する事でtextboxへの(大した事ない)情報表示と、pictureboxの画像が切り替わります。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO; // file / directory文字列処理など
using OpenCvSharp; // 今回はNuGetでOpenCV sharp 3を導入(2が見つからなくなっていたので)
using OpenCvSharp.Extensions; // bitmap converterの為
namespace DragDrop01
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
listBox1.AllowDrop = true; // プロパティを編集してもよい(やらないとEnterイベントが発生しない模様)
}
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
} else
{
e.Effect = DragDropEffects.None;
}
}
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
string[] fileName = (string[])e.Data.GetData(DataFormats.FileDrop, false);
listBox1.Items.AddRange(fileName);
}
// listboxの選択変更
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string currentItem = listBox1.SelectedItem.ToString(); // アイテムを取得する
// int index = listBox1.FindString(currentItem); // (↑のアイテムから)indexを取得する事も可
textBox1.Text = Path.GetDirectoryName(currentItem);
textBox2.Text = Path.GetFileName(currentItem);
Mat image = new Mat(currentItem);
string imageSize = image.Width.ToString() + " : " + image.Height.ToString();
textBox3.Text = imageSize.ToString();
Cv2.Resize(image, image, new OpenCvSharp.Size(pictureBox1.Width, pictureBox1.Height));
pictureBox1.Image = BitmapConverter.ToBitmap(image);
}
}
}
以下をformに配置します。
picturebox : 画像表示用
textbox x 3 : ディレクトリ名表示・ファイル名表示・画像サイズ表示 (表示するだけなのでlabelでも可です)
listbox : ドラッグ & ドロップはこちらに対して行います
listboxにファイルをドラッグ & ドロップするとアイテムが増え、listboxのアイテムを選択する事でtextboxへの(大した事ない)情報表示と、pictureboxの画像が切り替わります。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO; // file / directory文字列処理など
using OpenCvSharp; // 今回はNuGetでOpenCV sharp 3を導入(2が見つからなくなっていたので)
using OpenCvSharp.Extensions; // bitmap converterの為
namespace DragDrop01
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
listBox1.AllowDrop = true; // プロパティを編集してもよい(やらないとEnterイベントが発生しない模様)
}
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
} else
{
e.Effect = DragDropEffects.None;
}
}
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
string[] fileName = (string[])e.Data.GetData(DataFormats.FileDrop, false);
listBox1.Items.AddRange(fileName);
}
// listboxの選択変更
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string currentItem = listBox1.SelectedItem.ToString(); // アイテムを取得する
// int index = listBox1.FindString(currentItem); // (↑のアイテムから)indexを取得する事も可
textBox1.Text = Path.GetDirectoryName(currentItem);
textBox2.Text = Path.GetFileName(currentItem);
Mat image = new Mat(currentItem);
string imageSize = image.Width.ToString() + " : " + image.Height.ToString();
textBox3.Text = imageSize.ToString();
Cv2.Resize(image, image, new OpenCvSharp.Size(pictureBox1.Width, pictureBox1.Height));
pictureBox1.Image = BitmapConverter.ToBitmap(image);
}
}
}
2017年10月15日日曜日
timerを使って画像を回転させてみる
続いて、timer1を張り付けて、defaultの100msec毎に回転角を変えて、アニメーションさせてみます。
カクカクしながらもアニメーションしてくれます(100msecなのでこんなもんでしょうか)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.Extensions;
namespace _06_affineRot
{
public partial class Form1 : Form
{
private double angle = 0.0;
private Mat procImage = new Mat(); // 縮小した表示用の画像(回転前)
public Form1()
{
InitializeComponent();
}
private void button_disp_Click(object sender, EventArgs e)
{
Mat matImage = new Mat(@"C:\Users\hoge\hogehoge.jpg");
procImage = new Mat();
// とりあえずリサイズしてみた (picuterBosのサイズにあわせています)
Cv2.Resize(matImage, procImage, new CvSize(320,240));
// 表示用bitmap変換
Image dispImage = BitmapConverter.ToBitmap(procImage);
pictureBox1.Image = dispImage;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
angle = (angle + 1.0) % 360.0;
Mat angledImage = AffineRotate(procImage, angle);
Image dispImage = BitmapConverter.ToBitmap(angledImage);
pictureBox1.Image = dispImage;
}
// affin変換で回転させてみる
private Mat AffineRotate(Mat srcImage, double angle)
{
Mat retImage = new Mat();
double scale = 1.0;
Point2f center = new Point2f(srcImage.Width / 2, srcImage.Height / 2);
Mat affineMatrix = Cv2.GetRotationMatrix2D(center, angle, scale);
Cv2.WarpAffine(srcImage, retImage, affineMatrix, srcImage.Size());
return retImage;
}
}
}
カクカクしながらもアニメーションしてくれます(100msecなのでこんなもんでしょうか)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.Extensions;
namespace _06_affineRot
{
public partial class Form1 : Form
{
private double angle = 0.0;
private Mat procImage = new Mat(); // 縮小した表示用の画像(回転前)
public Form1()
{
InitializeComponent();
}
private void button_disp_Click(object sender, EventArgs e)
{
Mat matImage = new Mat(@"C:\Users\hoge\hogehoge.jpg");
procImage = new Mat();
// とりあえずリサイズしてみた (picuterBosのサイズにあわせています)
Cv2.Resize(matImage, procImage, new CvSize(320,240));
// 表示用bitmap変換
Image dispImage = BitmapConverter.ToBitmap(procImage);
pictureBox1.Image = dispImage;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
angle = (angle + 1.0) % 360.0;
Mat angledImage = AffineRotate(procImage, angle);
Image dispImage = BitmapConverter.ToBitmap(angledImage);
pictureBox1.Image = dispImage;
}
// affin変換で回転させてみる
private Mat AffineRotate(Mat srcImage, double angle)
{
Mat retImage = new Mat();
double scale = 1.0;
Point2f center = new Point2f(srcImage.Width / 2, srcImage.Height / 2);
Mat affineMatrix = Cv2.GetRotationMatrix2D(center, angle, scale);
Cv2.WarpAffine(srcImage, retImage, affineMatrix, srcImage.Size());
return retImage;
}
}
}
2017年10月14日土曜日
Affine変換で画像を回転させてみる
まずは、ボタンを押すと回転された画像をpicture boxに表示するFormアプリを作ってみます。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.Extensions;
namespace _06_affineRot
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button_disp_Click(object sender, EventArgs e)
{
Mat matImage = new Mat(@"C:\Users\hoge\hogehoge.jpg");
Mat procImage = new Mat();
// とりあえずリサイズしてみた
Cv2.Resize(matImage, procImage, new CvSize(320,240));
// affine変換で回転させてみる
Point2f center = new Point2f(procImage.Width / 2, procImage.Height / 2);
double angle = -40.0;
double scale = 1.0;
Mat affineMatrix = Cv2.GetRotationMatrix2D(center, angle, scale);
Cv2.WarpAffine(procImage, procImage, affineMatrix, procImage.Size());
// 表示用bitmap変換
Image dispImage = BitmapConverter.ToBitmap(procImage);
pictureBox1.Image = dispImage;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.Extensions;
namespace _06_affineRot
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button_disp_Click(object sender, EventArgs e)
{
Mat matImage = new Mat(@"C:\Users\hoge\hogehoge.jpg");
Mat procImage = new Mat();
// とりあえずリサイズしてみた
Cv2.Resize(matImage, procImage, new CvSize(320,240));
// affine変換で回転させてみる
Point2f center = new Point2f(procImage.Width / 2, procImage.Height / 2);
double angle = -40.0;
double scale = 1.0;
Mat affineMatrix = Cv2.GetRotationMatrix2D(center, angle, scale);
Cv2.WarpAffine(procImage, procImage, affineMatrix, procImage.Size());
// 表示用bitmap変換
Image dispImage = BitmapConverter.ToBitmap(procImage);
pictureBox1.Image = dispImage;
}
}
}
2017年10月12日木曜日
特徴点を表示したり遊んでみる
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus; // コレ
using System.Diagnostics;
namespace _03_matTest
{
class Program
{
static void Main(string[] args)
{
/*
CvMat mat1 = new CvMat(10, 10, MatrixType.U16C1);
CvMat mat2 = new CvMat(320, 480, MatrixType.U8C3, new CvScalar(0,0,255));
using (new CvWindow(mat2))
{
Debug.WriteLine(mat2.Width + " : " + mat2.Height);
Debug.WriteLine(mat2.ElemDepth + " : " + mat2.ElemType);
Cv.WaitKey();
}
*/
Mat matImage = new Mat(@"C:\Users\hogehoge\\Pictures\hogehoge.jpg");
Mat grayImage = new Mat();
Cv2.CvtColor(matImage, grayImage, ColorConversion.RgbToGray);
/*
var indexer = matImage.GetGenericIndexer<Vec3b>();
var px = indexer[5, 5];
Debug.WriteLine(px[0] + ":" + px[1] + ":" + px[2]);
px[0] = 0; // B
px[1] = 0; // G
px[2] = 255; // R
indexer[5, 5] = px;
// var type = matImage.Type;
using (new Window("photo", matImage)) // ウィンドウを作成して画像を表示
*/
CvSize size = new CvSize(matImage.Width / 8, matImage.Height / 8);
Mat dispImage = new Mat();
Cv2.Resize(matImage, dispImage, size);
using (new Window("resized image", dispImage))
{
Cv.WaitKey();
}
Mat copyImage = dispImage.Clone(new Rect(0, 0, matImage.Width / 8, matImage.Height / 8)); // 画像をコピー(というかcloneなのでポインタではなく深い)
Mat bwImage = copyImage.Clone();
Cv2.CvtColor(bwImage, bwImage, ColorConversion.RgbToGray);
KeyPoint[] keypoints;
// Cv2.FAST(bwImage, out keypoints, 50, true); // FAST : cornerを検出する 桜の場合はコーナーだらけ
// Cv2.FAST(bwImage, out keypoints, 50, true); // 建物 : まあまあ
// Cv2.FAST(bwImage, out keypoints, 20, true); // 建物 : やや増える
Cv2.FAST(bwImage, out keypoints, 100, true); // 建物 : 減る
foreach (KeyPoint kp in keypoints)
{
dispImage.Circle(kp.Pt, 3, Scalar.Red, -1, LineType.AntiAlias, 0);
}
using (new Window("copy image", dispImage))
{
Cv2.WaitKey();
}
/*
using (new Window("gray image", grayImage))
{
Debug.WriteLine(grayImage.Width + " : " + grayImage.Height); // 4896 : 3264
Debug.WriteLine(grayImage.Depth() + " : " + grayImage.Type()); // 0 : CV_8UC1
Cv.WaitKey();
}
*/
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus; // コレ
using System.Diagnostics;
namespace _03_matTest
{
class Program
{
static void Main(string[] args)
{
/*
CvMat mat1 = new CvMat(10, 10, MatrixType.U16C1);
CvMat mat2 = new CvMat(320, 480, MatrixType.U8C3, new CvScalar(0,0,255));
using (new CvWindow(mat2))
{
Debug.WriteLine(mat2.Width + " : " + mat2.Height);
Debug.WriteLine(mat2.ElemDepth + " : " + mat2.ElemType);
Cv.WaitKey();
}
*/
Mat matImage = new Mat(@"C:\Users\hogehoge\\Pictures\hogehoge.jpg");
Mat grayImage = new Mat();
Cv2.CvtColor(matImage, grayImage, ColorConversion.RgbToGray);
/*
var indexer = matImage.GetGenericIndexer<Vec3b>();
var px = indexer[5, 5];
Debug.WriteLine(px[0] + ":" + px[1] + ":" + px[2]);
px[0] = 0; // B
px[1] = 0; // G
px[2] = 255; // R
indexer[5, 5] = px;
// var type = matImage.Type;
using (new Window("photo", matImage)) // ウィンドウを作成して画像を表示
*/
CvSize size = new CvSize(matImage.Width / 8, matImage.Height / 8);
Mat dispImage = new Mat();
Cv2.Resize(matImage, dispImage, size);
using (new Window("resized image", dispImage))
{
Cv.WaitKey();
}
Mat copyImage = dispImage.Clone(new Rect(0, 0, matImage.Width / 8, matImage.Height / 8)); // 画像をコピー(というかcloneなのでポインタではなく深い)
Mat bwImage = copyImage.Clone();
Cv2.CvtColor(bwImage, bwImage, ColorConversion.RgbToGray);
KeyPoint[] keypoints;
// Cv2.FAST(bwImage, out keypoints, 50, true); // FAST : cornerを検出する 桜の場合はコーナーだらけ
// Cv2.FAST(bwImage, out keypoints, 50, true); // 建物 : まあまあ
// Cv2.FAST(bwImage, out keypoints, 20, true); // 建物 : やや増える
Cv2.FAST(bwImage, out keypoints, 100, true); // 建物 : 減る
foreach (KeyPoint kp in keypoints)
{
dispImage.Circle(kp.Pt, 3, Scalar.Red, -1, LineType.AntiAlias, 0);
}
using (new Window("copy image", dispImage))
{
Cv2.WaitKey();
}
/*
using (new Window("gray image", grayImage))
{
Debug.WriteLine(grayImage.Width + " : " + grayImage.Height); // 4896 : 3264
Debug.WriteLine(grayImage.Depth() + " : " + grayImage.Type()); // 0 : CV_8UC1
Cv.WaitKey();
}
*/
}
}
}
2017年10月11日水曜日
MatをFormのpictureBoxに表示
BitmapConverterを使ってimageに指定するのが味噌
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
// 以下を追加
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.Extensions; // Bitmap変換に必要
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button_imageLoad_Click(object sender, EventArgs e)
{
Mat matOrgImage = new Mat(@"C:\Users\hoge\Pictures\hogehoge.jpg");
Mat matDispImage = new Mat();
CvSize size = new CvSize(pictureBox1.Width, pictureBox1.Height); // formのpicture boxのサイズにあわせた
Cv2.Resize(matOrgImage, matDispImage, size);
Image image = BitmapConverter.ToBitmap(matDispImage);
pictureBox1.Image = image;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
// 以下を追加
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;
using OpenCvSharp.Extensions; // Bitmap変換に必要
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button_imageLoad_Click(object sender, EventArgs e)
{
Mat matOrgImage = new Mat(@"C:\Users\hoge\Pictures\hogehoge.jpg");
Mat matDispImage = new Mat();
CvSize size = new CvSize(pictureBox1.Width, pictureBox1.Height); // formのpicture boxのサイズにあわせた
Cv2.Resize(matOrgImage, matDispImage, size);
Image image = BitmapConverter.ToBitmap(matDispImage);
pictureBox1.Image = image;
}
}
}
2017年10月9日月曜日
Matでグレースケール変換
Matの使い方が分かってきたので、CvtColorを使ってカラー画像をグレースケールに変換してみます。
Cv2 クラスにメソッドが用意されている模様。
色々用意されているメソッドもこれで使えそうです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus; // コレ
using System.Diagnostics;
namespace _03_matTest
{
class Program
{
static void Main(string[] args)
{
Mat matImage = new Mat(@"C:\Users\hogehoge\Pictures\hoge.jpg");
Mat grayImage = new Mat(); // グレースケール用Mat
// グレースケール変換 (param3はインテリセンスに頼ります)
Cv2.CvtColor(matImage, grayImage, ColorConversion.RgbToGray);
using (new Window("gray image", grayImage))
{
Debug.WriteLine(matImage.Width + " : " + grayImage.Height); // 4896 : 3264
Debug.WriteLine(grayImage.Depth() + " : " + grayImage.Type()); // 0 : CV_8UC1
Cv.WaitKey();
}
}
}
}
Cv2 クラスにメソッドが用意されている模様。
色々用意されているメソッドもこれで使えそうです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus; // コレ
using System.Diagnostics;
namespace _03_matTest
{
class Program
{
static void Main(string[] args)
{
Mat matImage = new Mat(@"C:\Users\hogehoge\Pictures\hoge.jpg");
Mat grayImage = new Mat(); // グレースケール用Mat
// グレースケール変換 (param3はインテリセンスに頼ります)
Cv2.CvtColor(matImage, grayImage, ColorConversion.RgbToGray);
using (new Window("gray image", grayImage))
{
Debug.WriteLine(matImage.Width + " : " + grayImage.Height); // 4896 : 3264
Debug.WriteLine(grayImage.Depth() + " : " + grayImage.Type()); // 0 : CV_8UC1
Cv.WaitKey();
}
}
}
}
2017年10月8日日曜日
Matを使うのがイマ風?
openCvSharp2 以降はC++ interfaceを使えるので、indexerでピクセルを触りたい場合は "Mat"を使うとよいようだ (IplImage, CvMatではなく)
---
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// ここから追加
using OpenCvSharp;
using OpenCvSharp.CPlusPlus; // Matを使うなら必要
using System.Diagnostics;
namespace _03_matTest
{
class Program
{
static void Main(string[] args)
{
Mat matImage = new Mat(@"C:\Users\hoge\Pictures\hoge.jpg");
var indexer = matImage.GetGenericIndexer<Vec3b>(); // indexer でアクセスする例
var px = indexer[5, 5]; // x:5 y:5のpixel
Debug.WriteLine(px[0] + ":" + px[1] + ":" + px[2]);
px[0] = 0; // B
px[1] = 0; // G
px[2] = 255; // R
indexer[5, 5] = px;
using (new Window("photo", matImage)) // ウィンドウを作成して画像を表示
{
Debug.WriteLine(matImage.Width + " : " + matImage.Height);
Cv.WaitKey();
}
}
}
}
参考にさせていただきました
http://schima.hatenablog.com/entry/2014/03/29/140106
http://sourcechord.hatenablog.com/entry/2016/08/15/235654
---
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// ここから追加
using OpenCvSharp;
using OpenCvSharp.CPlusPlus; // Matを使うなら必要
using System.Diagnostics;
namespace _03_matTest
{
class Program
{
static void Main(string[] args)
{
Mat matImage = new Mat(@"C:\Users\hoge\Pictures\hoge.jpg");
var indexer = matImage.GetGenericIndexer<Vec3b>(); // indexer でアクセスする例
var px = indexer[5, 5]; // x:5 y:5のpixel
Debug.WriteLine(px[0] + ":" + px[1] + ":" + px[2]);
px[0] = 0; // B
px[1] = 0; // G
px[2] = 255; // R
indexer[5, 5] = px;
using (new Window("photo", matImage)) // ウィンドウを作成して画像を表示
{
Debug.WriteLine(matImage.Width + " : " + matImage.Height);
Cv.WaitKey();
}
}
}
}
参考にさせていただきました
http://schima.hatenablog.com/entry/2014/03/29/140106
http://sourcechord.hatenablog.com/entry/2016/08/15/235654
2017年10月4日水曜日
Remote Desktop から Windows Media player でAudio CDが"不明"になる
Windows Media Playerだけの問題なのかは不明ですが、グループポリシーの設定変更で解決できました。
1. Administratorでログイン
2. スタート -> "グループポリシー" で検索 -> "グループポリシーの編集"を選択
3. コンピュータの構成 -> 管理用テンプレート -> システム -> リムーバブル領域
4. 2すべてのリムーバブル記憶域:リモート セッションでの直接アクセスを許可する" を有効にする
こちらを参考にさせていただきました。
http://d.hatena.ne.jp/kamenoi/20170210/p1
1. Administratorでログイン
2. スタート -> "グループポリシー" で検索 -> "グループポリシーの編集"を選択
3. コンピュータの構成 -> 管理用テンプレート -> システム -> リムーバブル領域
4. 2すべてのリムーバブル記憶域:リモート セッションでの直接アクセスを許可する" を有効にする
こちらを参考にさせていただきました。
http://d.hatena.ne.jp/kamenoi/20170210/p1
2017年10月3日火曜日
物体のエッジ検出フィルタ(canyフィルタ)をかけてみる
例によってまるパクリです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
namespace _02_cameraFilter
{
class Program
{
static void Main(string[] args)
{
ShowCamera();
}
static void ShowCamera()
{
//カメラ映像を表示
int cameraPort = 0;
using (var capture = Cv.CreateCameraCapture(cameraPort))
{
IplImage frame = new IplImage();
// W640 x H480 (default resolution)のウィンドウを作る
int w = 640, h = 480;
// カメラ映像の画サイズ設定
Cv.SetCaptureProperty(capture, CaptureProperty.FrameWidth, w);
Cv.SetCaptureProperty(capture, CaptureProperty.FrameHeight, h);
//ESCキー押さない限り
while (Cv.WaitKey(1) != 27)
{
// 画像の取得
frame = Cv.QueryFrame(capture);
if (frame != null)
{
int threshold1 = 120;
int threshold2 = 80;
//trimmingするための座標
int trimmingX = 50;
int trimmingY = 20;
int trimmingW = 300;
int trimmingH = 300;
IplImage edgeFrame = new IplImage(frame.Width, frame.Height, BitDepth.U8, 1);
frame.Canny(edgeFrame, threshold1, threshold2);
//frameをトリミングする
IplImage trimmedFrame = trimming(edgeFrame, trimmingX, trimmingY, trimmingW, trimmingH);
Cv.ShowImage("Liveカメラ(元)", frame);
Cv.ShowImage("Liveカメラ(Edge)", edgeFrame);
Cv.ShowImage("抽出した映像", trimmedFrame);
//メモリ解放
Cv.ReleaseImage(trimmedFrame);
Cv.ReleaseImage(edgeFrame);
Cv.ReleaseImage(frame);
}
}
//ESCキーが押されたら
//全ての画像やwindowを削除
Cv.DestroyAllWindows();
capture.Dispose();
}
}
//frameをtrimmingする
static IplImage trimming(IplImage src, int x, int y, int width, int height)
{
IplImage dest = new IplImage(width, height, src.Depth, src.NChannels);
Cv.SetImageROI(src, new CvRect(x, y, width, height));
dest = Cv.CloneImage(src);
Cv.ResetImageROI(src);
return dest;
}
}
}
参照
http://www.thedesignium.com/development/8237
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
namespace _02_cameraFilter
{
class Program
{
static void Main(string[] args)
{
ShowCamera();
}
static void ShowCamera()
{
//カメラ映像を表示
int cameraPort = 0;
using (var capture = Cv.CreateCameraCapture(cameraPort))
{
IplImage frame = new IplImage();
// W640 x H480 (default resolution)のウィンドウを作る
int w = 640, h = 480;
// カメラ映像の画サイズ設定
Cv.SetCaptureProperty(capture, CaptureProperty.FrameWidth, w);
Cv.SetCaptureProperty(capture, CaptureProperty.FrameHeight, h);
//ESCキー押さない限り
while (Cv.WaitKey(1) != 27)
{
// 画像の取得
frame = Cv.QueryFrame(capture);
if (frame != null)
{
int threshold1 = 120;
int threshold2 = 80;
//trimmingするための座標
int trimmingX = 50;
int trimmingY = 20;
int trimmingW = 300;
int trimmingH = 300;
IplImage edgeFrame = new IplImage(frame.Width, frame.Height, BitDepth.U8, 1);
frame.Canny(edgeFrame, threshold1, threshold2);
//frameをトリミングする
IplImage trimmedFrame = trimming(edgeFrame, trimmingX, trimmingY, trimmingW, trimmingH);
Cv.ShowImage("Liveカメラ(元)", frame);
Cv.ShowImage("Liveカメラ(Edge)", edgeFrame);
Cv.ShowImage("抽出した映像", trimmedFrame);
//メモリ解放
Cv.ReleaseImage(trimmedFrame);
Cv.ReleaseImage(edgeFrame);
Cv.ReleaseImage(frame);
}
}
//ESCキーが押されたら
//全ての画像やwindowを削除
Cv.DestroyAllWindows();
capture.Dispose();
}
}
//frameをtrimmingする
static IplImage trimming(IplImage src, int x, int y, int width, int height)
{
IplImage dest = new IplImage(width, height, src.Depth, src.NChannels);
Cv.SetImageROI(src, new CvRect(x, y, width, height));
dest = Cv.CloneImage(src);
Cv.ResetImageROI(src);
return dest;
}
}
}
参照
http://www.thedesignium.com/development/8237
2017年10月2日月曜日
OpenCvSharpでカメラ画像を表示してみる
べた書きするとこんな感じ
カメラの番号が異なる場合はcameraPortを変更します
(タリーランプがついていれば大丈夫。異なっていればusingでexception発生)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
namespace _01_cameraThrough
{
class Program
{
static void Main(string[] args)
{
ShowCamera();
}
static void ShowCamera()
{
//カメラ映像を表示
int cameraPort = 0;
using (var capture = Cv.CreateCameraCapture(cameraPort))
{
IplImage frame = new IplImage();
// W640 x H480 (default resolution)のウィンドウを作る
int w = 640, h = 480;
// カメラ映像の画サイズ設定
Cv.SetCaptureProperty(capture, CaptureProperty.FrameWidth, w);
Cv.SetCaptureProperty(capture, CaptureProperty.FrameHeight, h);
//ESCキー押さない限り
while (Cv.WaitKey(1) != 27)
{
// 画像の取得
frame = Cv.QueryFrame(capture);
if (frame != null)
{
//frameを表示
Cv.ShowImage("Liveカメラ", frame);
}
}
//ESCキーが押されたら
//全ての画像やwindowを削除
Cv.DestroyAllWindows();
capture.Dispose();
}
}
}
}
参考にさせていただきました
http://www.thedesignium.com/development/8237
カメラの番号が異なる場合はcameraPortを変更します
(タリーランプがついていれば大丈夫。異なっていればusingでexception発生)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
namespace _01_cameraThrough
{
class Program
{
static void Main(string[] args)
{
ShowCamera();
}
static void ShowCamera()
{
//カメラ映像を表示
int cameraPort = 0;
using (var capture = Cv.CreateCameraCapture(cameraPort))
{
IplImage frame = new IplImage();
// W640 x H480 (default resolution)のウィンドウを作る
int w = 640, h = 480;
// カメラ映像の画サイズ設定
Cv.SetCaptureProperty(capture, CaptureProperty.FrameWidth, w);
Cv.SetCaptureProperty(capture, CaptureProperty.FrameHeight, h);
//ESCキー押さない限り
while (Cv.WaitKey(1) != 27)
{
// 画像の取得
frame = Cv.QueryFrame(capture);
if (frame != null)
{
//frameを表示
Cv.ShowImage("Liveカメラ", frame);
}
}
//ESCキーが押されたら
//全ての画像やwindowを削除
Cv.DestroyAllWindows();
capture.Dispose();
}
}
}
}
参考にさせていただきました
http://www.thedesignium.com/development/8237
表示画像を縮小してみる(Resize)
こんな感じで...
using (var img = new IplImage(@"C:\Users\hogehohe\Pictures\hoge.png")) // 画像を読み込み
{
CvSize size = new CvSize(img.Width / 2, img.Height / 2);
IplImage img2 = new IplImage(size,img.Depth, img.NChannels); // サイズ違いのimgを作成
Cv.Resize(img, img2); // リサイズ
using (new CvWindow(img2)) // ウィンドウを作成して画像を表示
{
Cv.WaitKey();
}
}
using (var img = new IplImage(@"C:\Users\hogehohe\Pictures\hoge.png")) // 画像を読み込み
{
CvSize size = new CvSize(img.Width / 2, img.Height / 2);
IplImage img2 = new IplImage(size,img.Depth, img.NChannels); // サイズ違いのimgを作成
Cv.Resize(img, img2); // リサイズ
using (new CvWindow(img2)) // ウィンドウを作成して画像を表示
{
Cv.WaitKey();
}
}
2017年10月1日日曜日
OpenCvSharpのはじめの一歩
1. Visual Studio 2015などで、File -> プロジェクトの作成
2. ツール -> NuGeパッケージマネージャ -> 参照 -> OpenCvSharp で検索 -> インストール(チェックボックスをチェックしてインストールボタン)
3. 以下のコードを書く
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp; // 追加
namespace consoleApplicationSample
{
class Program
{
static void Main(string[] args)
{
using (var img = new IplImage(@"C:\Users\hogehoge\Pictures\hoge.png")) // 画像を読み込み
{
Cv.Not(img, img); // 画像をネガポジ反転
using (new CvWindow(img)) // ウィンドウを作成して画像を表示
{
Cv.WaitKey();
}
}
}
}
}
2. ツール -> NuGeパッケージマネージャ -> 参照 -> OpenCvSharp で検索 -> インストール(チェックボックスをチェックしてインストールボタン)
3. 以下のコードを書く
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp; // 追加
namespace consoleApplicationSample
{
class Program
{
static void Main(string[] args)
{
using (var img = new IplImage(@"C:\Users\hogehoge\Pictures\hoge.png")) // 画像を読み込み
{
Cv.Not(img, img); // 画像をネガポジ反転
using (new CvWindow(img)) // ウィンドウを作成して画像を表示
{
Cv.WaitKey();
}
}
}
}
}
2017年6月28日水曜日
Navigation Itemのタイトルを表示する
Navigation controllerでタイトルを表示したい場合の例です。
画面遷移後のviewDidLoadで表示を行っています。
var hoge : String? < 前の画面から設定させる場合の箱
...
override func viewDidLoad() {
...
// Navigation controller タイトル表示
if let dispTitle = hoge {
self.title = hoge
}
前の画面でタイトルを指定したい場合などは、前の画面のprepareForSegue(遷移直前に呼ばれるメソッド)で以下のようにします。
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "hogehogehoge" {
...
(segue.destinationViewController as? hogehogeViewController)!.hoge = hogedata
画面遷移後のviewDidLoadで表示を行っています。
var hoge : String? < 前の画面から設定させる場合の箱
...
override func viewDidLoad() {
...
// Navigation controller タイトル表示
if let dispTitle = hoge {
self.title = hoge
}
前の画面でタイトルを指定したい場合などは、前の画面のprepareForSegue(遷移直前に呼ばれるメソッド)で以下のようにします。
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "hogehogehoge" {
...
(segue.destinationViewController as? hogehogeViewController)!.hoge = hogedata
2017年5月17日水曜日
NSTimerを使って時計表示をしてみる(2)
Timerの生成とRun Loopの登録を別に行う方法です。
NSTimerは毎回作らないといけない模様 (使いまわそうとしても開始しなかった為)
---
import UIKit
class ViewController: UIViewController {
var count:Int = 0
var timer:NSTimer? = nil // タイマー
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
/*
timer = NSTimer(timeInterval: 0.01, // 繰り返し時間(秒)
target: self,
selector: (#selector(ViewController.DispWatchCount)), // ハンドラの指定
userInfo: nil,
repeats: true // 繰り返し
)
NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSDefaultRunLoopMode)
*/
}
func update() {
print("timer")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBOutlet weak var DispTime: UILabel!
@IBAction func stop(sender: AnyObject) {
timer?.invalidate()
}
@IBAction func ButtonStart(sender: AnyObject) {
timer = NSTimer(timeInterval: 0.01, // 繰り返し時間(秒)
target: self,
selector: (#selector(ViewController.DispWatchCount)), // ハンドラの指定
userInfo: nil,
repeats: true // 繰り返し
) // Timerを生成
NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSDefaultRunLoopMode) // timerを開始 (Run Loopに登録)
}
@IBAction func ButtonStop(sender: AnyObject) {
timer?.invalidate() // timerを停止
}
// Timer handler
func DispWatchCount(){
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "HH:mm:ss:SS"
let dispTime = formatter.stringFromDate(date)
/* メンバーにアクセスする場合
let calender = NSCalendar.currentCalendar()
let component = calender.components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second], fromDate: date)
let dispTime = String(component.hour) + ":" + String(component.minute) + ":" + String(component.second)
*/
DispTime.text = dispTime
// count += 1
// DispTime.text = String(count)
}
}
NSTimerは毎回作らないといけない模様 (使いまわそうとしても開始しなかった為)
---
import UIKit
class ViewController: UIViewController {
var count:Int = 0
var timer:NSTimer? = nil // タイマー
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
/*
timer = NSTimer(timeInterval: 0.01, // 繰り返し時間(秒)
target: self,
selector: (#selector(ViewController.DispWatchCount)), // ハンドラの指定
userInfo: nil,
repeats: true // 繰り返し
)
NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSDefaultRunLoopMode)
*/
}
func update() {
print("timer")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBOutlet weak var DispTime: UILabel!
@IBAction func stop(sender: AnyObject) {
timer?.invalidate()
}
@IBAction func ButtonStart(sender: AnyObject) {
timer = NSTimer(timeInterval: 0.01, // 繰り返し時間(秒)
target: self,
selector: (#selector(ViewController.DispWatchCount)), // ハンドラの指定
userInfo: nil,
repeats: true // 繰り返し
) // Timerを生成
NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSDefaultRunLoopMode) // timerを開始 (Run Loopに登録)
}
@IBAction func ButtonStop(sender: AnyObject) {
timer?.invalidate() // timerを停止
}
// Timer handler
func DispWatchCount(){
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "HH:mm:ss:SS"
let dispTime = formatter.stringFromDate(date)
/* メンバーにアクセスする場合
let calender = NSCalendar.currentCalendar()
let component = calender.components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second], fromDate: date)
let dispTime = String(component.hour) + ":" + String(component.minute) + ":" + String(component.second)
*/
DispTime.text = dispTime
// count += 1
// DispTime.text = String(count)
}
}
2017年5月16日火曜日
NSTimerを使って時計表示をしてみる(1)
timerの生成とRunloopへの登録...を同時に行う方法らしいです
1. タイマーを起動する
param3がtimerハンドラを指定
NSTimer.scheduledTimerWithTimeInterval(
0.01, // 繰り返す時間(秒)
target: self,
selector: (#selector(ViewController.DispWatchCount)), // ハンドラ
userInfo: nil,
repeats: true //リピート実行
)
2. timerハンドラの記述
func DispWatchCount(){
...
}
ちなみに等幅フォントとして時計表示部分は Courier 50.0 を使用
---
import UIKit
class ViewController: UIViewController {
var count:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: (#selector(ViewController.DispWatchCount)), userInfo: nil, repeats: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBOutlet weak var DispTime: UILabel!
// Timer handler
func DispWatchCount(){
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "HH:mm:ss:SS"
let dispTime = formatter.stringFromDate(date)
/* メンバーにアクセスする場合
let calender = NSCalendar.currentCalendar()
let component = calender.components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second], fromDate: date)
let dispTime = String(component.hour) + ":" + String(component.minute) + ":" + String(component.second)
*/
DispTime.text = dispTime
}
}
1. タイマーを起動する
param3がtimerハンドラを指定
NSTimer.scheduledTimerWithTimeInterval(
0.01, // 繰り返す時間(秒)
target: self,
selector: (#selector(ViewController.DispWatchCount)), // ハンドラ
userInfo: nil,
repeats: true //リピート実行
)
2. timerハンドラの記述
func DispWatchCount(){
...
}
ちなみに等幅フォントとして時計表示部分は Courier 50.0 を使用
---
import UIKit
class ViewController: UIViewController {
var count:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: (#selector(ViewController.DispWatchCount)), userInfo: nil, repeats: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBOutlet weak var DispTime: UILabel!
// Timer handler
func DispWatchCount(){
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "HH:mm:ss:SS"
let dispTime = formatter.stringFromDate(date)
/* メンバーにアクセスする場合
let calender = NSCalendar.currentCalendar()
let component = calender.components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second], fromDate: date)
let dispTime = String(component.hour) + ":" + String(component.minute) + ":" + String(component.second)
*/
DispTime.text = dispTime
}
}
2017年5月15日月曜日
JSONを読む(Array編)
こんな感じのJSONを読みます
{{"midashi":
[{"hoge":"1", "imageurl":"htt://www.hoge.com/uri01.png"},
{"hoge":"2", "imageurl":"htt://www.hoge.com/uri02.png"},
{"hoge":"3", "imageurl":"htt://www.hoge.com/uri03.png"}]
}
// NSUrlSessionの取得ハンドラ
func onFinishGetUri(data: NSData?, res: NSURLResponse?, error: NSError?){
var dict:NSDictionary
do{
dict = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
let imageList = dict["midashi"] as! NSArray
for image in imageList{
let url = image["imageurl"] as! String
print(url)
getList.append(url) // 詰め直してみる
}
// index0のurlを取得
print(getList[0])
} catch {
print("error")
return
}
}
{{"midashi":
[{"hoge":"1", "imageurl":"htt://www.hoge.com/uri01.png"},
{"hoge":"2", "imageurl":"htt://www.hoge.com/uri02.png"},
{"hoge":"3", "imageurl":"htt://www.hoge.com/uri03.png"}]
}
// NSUrlSessionの取得ハンドラ
func onFinishGetUri(data: NSData?, res: NSURLResponse?, error: NSError?){
var dict:NSDictionary
do{
dict = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
let imageList = dict["midashi"] as! NSArray
for image in imageList{
let url = image["imageurl"] as! String
print(url)
getList.append(url) // 詰め直してみる
}
// index0のurlを取得
print(getList[0])
} catch {
print("error")
return
}
}
2017年5月14日日曜日
JSONを読む(Dictionary編)
こんな感じのデータのvalueを読みます
{"hogedata":"http://hoge.com/image/hoge.png"}
// NSUrlSessionのハンドラ
func onFinishUri(data: NSData?, res: NSURLResponse?, error: NSError?){
var dict:NSDictionary
do{
dict = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
// let str = String(data)
// print(str) // {"hogedata":"http://hoge.com/image/hoge.png"}
let uri = dict["hogedata"] as! String // URLを取得
print(uri)
} catch {
print("error")
return
}
}
{"hogedata":"http://hoge.com/image/hoge.png"}
// NSUrlSessionのハンドラ
func onFinishUri(data: NSData?, res: NSURLResponse?, error: NSError?){
var dict:NSDictionary
do{
dict = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
// let str = String(data)
// print(str) // {"hogedata":"http://hoge.com/image/hoge.png"}
let uri = dict["hogedata"] as! String // URLを取得
print(uri)
} catch {
print("error")
return
}
}
2017年5月13日土曜日
NSUrlSessionでハンドラを指定して画像を取得・表示する
1. UIImageをMain.storyboardに貼る
2. UIImageからviewController.swiftにIBOutletを貼る
3. NSUrlSessinoで取得した時のハンドラを書く
// 画像を取得した時に呼び出されるハンドラ
func onFinishImage(data: NSData?, res: NSURLResponse?, error: NSError?){
uiImage = UIImage(data: data!)!
// バックグラウンドだとUIの処理が出来ないので、メインスレッドでUIの処理を行わせる.
dispatch_async(dispatch_get_main_queue(), {
self.uiImageView.image = self.uiImage
})
// 続きの処理があればこの辺に書いておく
}
4. NSUrlSessinでデータを取得する処理を書く(データ取得後は↑のハンドラを呼び出すようにする)
func getImageImg(uri:String){
let url = NSURL(string: uri)
let urlSession = NSURLSession.sharedSession()
let task = urlSession.dataTaskWithURL(url!, completionHandler: onFinishImage)
task.resume()
}
5. ViewDidLoadなどで↑を呼び出す
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let urlString = "http://hogehoge.co.jp/hoge.img"
getImageImg(urlString)
}
2. UIImageからviewController.swiftにIBOutletを貼る
3. NSUrlSessinoで取得した時のハンドラを書く
// 画像を取得した時に呼び出されるハンドラ
func onFinishImage(data: NSData?, res: NSURLResponse?, error: NSError?){
uiImage = UIImage(data: data!)!
// バックグラウンドだとUIの処理が出来ないので、メインスレッドでUIの処理を行わせる.
dispatch_async(dispatch_get_main_queue(), {
self.uiImageView.image = self.uiImage
})
// 続きの処理があればこの辺に書いておく
}
4. NSUrlSessinでデータを取得する処理を書く(データ取得後は↑のハンドラを呼び出すようにする)
func getImageImg(uri:String){
let url = NSURL(string: uri)
let urlSession = NSURLSession.sharedSession()
let task = urlSession.dataTaskWithURL(url!, completionHandler: onFinishImage)
task.resume()
}
5. ViewDidLoadなどで↑を呼び出す
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let urlString = "http://hogehoge.co.jp/hoge.img"
getImageImg(urlString)
}
2017年4月20日木曜日
AVSpeechSynthesizerでテキスト読み上げ
テキストだけ差し替える方法があるかもしれないけど、読み上げテキストで初期化する方法でも大丈夫。
import UIKit
import AVFoundation
class ViewController: UIViewController {
var talker = AVSpeechSynthesizer()
let talkTxt = "こんにちわ、今日はいい天気ですね"
let talkText2 = "テキスト2"
let talkTextEng = "hello"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// 読み上げ内容を初期化
var utterance = AVSpeechUtterance(string: talkTxt)
// 日本語
utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")
// 読み上げ
self.talker.speakUtterance(utterance)
// 2回目
utterance = AVSpeechUtterance(string: talkText2)
utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP") // defaultは英語なので毎回指定
self.talker.speakUtterance(utterance)
// 英語文を日本語で(読める)
utterance = AVSpeechUtterance(string: talkTextEng)
utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")
self.talker.speakUtterance(utterance)
// utterance.speechString = "こんにちわ" // get onlyなのでテキストのみ差し替えはできない?
// self.talker.speakUtterance(utterance)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
import UIKit
import AVFoundation
class ViewController: UIViewController {
var talker = AVSpeechSynthesizer()
let talkTxt = "こんにちわ、今日はいい天気ですね"
let talkText2 = "テキスト2"
let talkTextEng = "hello"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// 読み上げ内容を初期化
var utterance = AVSpeechUtterance(string: talkTxt)
// 日本語
utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")
// 読み上げ
self.talker.speakUtterance(utterance)
// 2回目
utterance = AVSpeechUtterance(string: talkText2)
utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP") // defaultは英語なので毎回指定
self.talker.speakUtterance(utterance)
// 英語文を日本語で(読める)
utterance = AVSpeechUtterance(string: talkTextEng)
utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")
self.talker.speakUtterance(utterance)
// utterance.speechString = "こんにちわ" // get onlyなのでテキストのみ差し替えはできない?
// self.talker.speakUtterance(utterance)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
2017年4月5日水曜日
optionalとアンラップ
- nilを許可する場合はOptional型として "?"をつける
- 使用するときはアンラップ < "!"で強制アンラップ
let unlap = optionalString!
- オプショナルバインディングで安全にアンラップ
if let opt = optionalString { // オプショナルバインディングでfalse
print("アンラップしました -> " + opt)
}
// optionalとは??
var nonOptionalString:String = "hello" // optionalじゃなくString型
print(nonOptionalString)
nonOptionalString = "hoge"
print(nonOptionalString)
// nonOptionalString = nil // ここでエラー "nil cannot be assigned to type 'String'
// print(nonOptionalString) // nilを入れることが出来ない為
// optional型で宣言
var optionalString:String? = "hello" // ?をつけるとOptional型になる
print(optionalString) // Optinal("hello")と表示される
optionalString = nil // nil代入もOK
print(optionalString) // "nil"と表示される
if let opt = optionalString { // オプショナルバインディングでfalse
print("アンラップしました -> " + opt)
} else {
print("nilが入っている") // こっちが表示される
}
optionalString = "hoge"
if let opt = optionalString { // オプショナルバインディングでアンラップ
print("アンラップしました -> " + opt) // アンラップされたこっちが表示される
} else {
print("nilが入っている")
}
- 使用するときはアンラップ < "!"で強制アンラップ
let unlap = optionalString!
- オプショナルバインディングで安全にアンラップ
if let opt = optionalString { // オプショナルバインディングでfalse
print("アンラップしました -> " + opt)
}
// optionalとは??
var nonOptionalString:String = "hello" // optionalじゃなくString型
print(nonOptionalString)
nonOptionalString = "hoge"
print(nonOptionalString)
// nonOptionalString = nil // ここでエラー "nil cannot be assigned to type 'String'
// print(nonOptionalString) // nilを入れることが出来ない為
// optional型で宣言
var optionalString:String? = "hello" // ?をつけるとOptional型になる
print(optionalString) // Optinal("hello")と表示される
optionalString = nil // nil代入もOK
print(optionalString) // "nil"と表示される
if let opt = optionalString { // オプショナルバインディングでfalse
print("アンラップしました -> " + opt)
} else {
print("nilが入っている") // こっちが表示される
}
optionalString = "hoge"
if let opt = optionalString { // オプショナルバインディングでアンラップ
print("アンラップしました -> " + opt) // アンラップされたこっちが表示される
} else {
print("nilが入っている")
}
2017年4月2日日曜日
http requestをNSURLSessionのdelegateで
NRURLSessionでhttp requestの結果をdelegateで受けてみます。
//
// ViewController.swift
//
import UIKit
class ViewController: UIViewController, NSURLSessionDelegate, NSURLSessionDataDelegate {
@IBOutlet weak var urlDataDisp: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
getUrlData("http://tantan2014.blogspot.jp/2017/01/mapkit-viewannotation.html")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getUrlData(targetUri: String){
// 通信用のConfigを生成.
let config: NSURLSessionConfiguration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("backgroundTask")
// Sessionを生成.
let session: NSURLSession = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
// 通信先のURLを生成.
let url: NSURL = NSURL(string: targetUri as String)!
// タスクの生成.
let task: NSURLSessionDataTask = session.dataTaskWithURL(url)
// タスクの実行.
task.resume()
}
/*
通信が終了したときに呼び出されるデリゲート.
*/
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
print("NSURLSessionDataTask")
// 帰ってきたデータを文字列に変換.
let getData: NSString = NSString(data: data, encoding: NSUTF8StringEncoding)!
// バックグラウンドだとUIの処理が出来ないので、メインスレッドでUIの処理を行わせる.
dispatch_async(dispatch_get_main_queue(), {
self.urlDataDisp.text = getData as String
})
}
/*
バックグラウンドからフォアグラウンドの復帰時に呼び出されるデリゲート.
*/
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
print("URLSessionDidFinishEventsForBackgroundURLSession")
}
}
ご説明はこちらが詳しいです。
http://qiita.com/aKentaKoyama/items/96a979ab3a140e7b39ec
//
// ViewController.swift
//
import UIKit
class ViewController: UIViewController, NSURLSessionDelegate, NSURLSessionDataDelegate {
@IBOutlet weak var urlDataDisp: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
getUrlData("http://tantan2014.blogspot.jp/2017/01/mapkit-viewannotation.html")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getUrlData(targetUri: String){
// 通信用のConfigを生成.
let config: NSURLSessionConfiguration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("backgroundTask")
// Sessionを生成.
let session: NSURLSession = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
// 通信先のURLを生成.
let url: NSURL = NSURL(string: targetUri as String)!
// タスクの生成.
let task: NSURLSessionDataTask = session.dataTaskWithURL(url)
// タスクの実行.
task.resume()
}
/*
通信が終了したときに呼び出されるデリゲート.
*/
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
print("NSURLSessionDataTask")
// 帰ってきたデータを文字列に変換.
let getData: NSString = NSString(data: data, encoding: NSUTF8StringEncoding)!
// バックグラウンドだとUIの処理が出来ないので、メインスレッドでUIの処理を行わせる.
dispatch_async(dispatch_get_main_queue(), {
self.urlDataDisp.text = getData as String
})
}
/*
バックグラウンドからフォアグラウンドの復帰時に呼び出されるデリゲート.
*/
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
print("URLSessionDidFinishEventsForBackgroundURLSession")
}
}
ご説明はこちらが詳しいです。
http://qiita.com/aKentaKoyama/items/96a979ab3a140e7b39ec
2017年2月27日月曜日
メールの送信をしてみる
MFMailComposeViewController を使うと、
- Swiftのアプリで送信先・題名・本文を生成
- メール送信アプリで送信(iPhoneなどのアカウントで)
という動作ができるようです。
(androidのintentのような感じ)
準備 : MessageUI.frameworkをlink libraryに追加
1. プロジェクトを選択
2. Build Phasesタブ -> Link Binary With Libralies
3. MessageUI.frameworkを選択
コード上のポイント
- ViewControllerに MFMailComposeViewControllerDelegate を追加
- viewDidLoadedに
composeVC = MFMailComposeViewController() を追加
- composeVCに対して、to/cc/bcc/subject/bodyを追加する
- self.presentViewController(composeVC, animated: true, completion: nil) でメール画面に遷移
- delegateに以下を追加
self.dismissViewControllerAnimated(true, completion: nil)
---
import UIKit
import MessageUI
class ViewController: UIViewController, MFMailComposeViewControllerDelegate{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// メール対応
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func buttonA(sender: AnyObject) {
makeFixedForm("本文a")
}
@IBAction func buttonB(sender: AnyObject) {
makeFixedForm("本文b")
}
// メール定型文書作成
func makeFixedForm(subj:String){
let toRecipients = ["送信先1", "送信先2"]
let ccRecipients = ["cc送信先"]
let bccRecipients = [""]
let subject = subj
let messageBody = "本文です"
sendMail(toRecipients, cc: ccRecipients, bcc: bccRecipients, subj: subject, msg: messageBody)
}
// 終了デリゲート
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
if result == MFMailComposeResultCancelled {
print("canceld")
} else if result == MFMailComposeResultSaved {
print("saved")
} else if result == MFMailComposeResultSent {
print("sent")
} else if result == MFMailComposeResultFailed {
print("failed")
}
self.dismissViewControllerAnimated(true, completion: nil)
}
// 引数の内容でメールアプリを起動する
func sendMail(to:[String], cc:[String], bcc:[String], subj:String, msg: String){
if !MFMailComposeViewController.canSendMail() {
print("Mail services are not available")
return
}
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
var toRecipients:[String] = []
var ccRecipients:[String] = []
var bccRecipients:[String] = []
var subject:String
var messageBody:String
// TODO:ちゃんとチェックする事
if(to.count != 0){
for toMember in to {
toRecipients.append(toMember)
}
}
if(cc.count != 0){
for ccMember in cc {
ccRecipients.append(ccMember)
}
}
if(bcc.count != 0){
for bccMember in bcc {
bccRecipients.append(bccMember)
}
}
subject = subj
messageBody = msg
// Configure the fields of the interface.
/*
composeVC.setToRecipients(["送信先1", "送信先2"]
composeVC.setBccRecipients(["cc送信先"])
composeVC.setSubject("こんにちわ!")
composeVC.setMessageBody("Hello from California!", isHTML: false)
*/
if(toRecipients.count > 0){
composeVC.setToRecipients(toRecipients)
}
if(ccRecipients.count > 0){
composeVC.setCcRecipients(ccRecipients)
}
if(bccRecipients.count > 0){
composeVC.setBccRecipients(bccRecipients)
}
if(subject.characters.count > 0){
composeVC.setSubject(subject)
}
if(messageBody.characters.count > 0){
composeVC.setMessageBody(messageBody, isHTML:false)
}
// Present the view controller modally.
self.presentViewController(composeVC, animated: true, completion: nil)
}
}
- Swiftのアプリで送信先・題名・本文を生成
- メール送信アプリで送信(iPhoneなどのアカウントで)
という動作ができるようです。
(androidのintentのような感じ)
準備 : MessageUI.frameworkをlink libraryに追加
1. プロジェクトを選択
2. Build Phasesタブ -> Link Binary With Libralies
3. MessageUI.frameworkを選択
コード上のポイント
- ViewControllerに MFMailComposeViewControllerDelegate を追加
- viewDidLoadedに
composeVC = MFMailComposeViewController() を追加
- composeVCに対して、to/cc/bcc/subject/bodyを追加する
- self.presentViewController(composeVC, animated: true, completion: nil) でメール画面に遷移
- delegateに以下を追加
self.dismissViewControllerAnimated(true, completion: nil)
---
import UIKit
import MessageUI
class ViewController: UIViewController, MFMailComposeViewControllerDelegate{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// メール対応
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func buttonA(sender: AnyObject) {
makeFixedForm("本文a")
}
@IBAction func buttonB(sender: AnyObject) {
makeFixedForm("本文b")
}
// メール定型文書作成
func makeFixedForm(subj:String){
let toRecipients = ["送信先1", "送信先2"]
let ccRecipients = ["cc送信先"]
let bccRecipients = [""]
let subject = subj
let messageBody = "本文です"
sendMail(toRecipients, cc: ccRecipients, bcc: bccRecipients, subj: subject, msg: messageBody)
}
// 終了デリゲート
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
if result == MFMailComposeResultCancelled {
print("canceld")
} else if result == MFMailComposeResultSaved {
print("saved")
} else if result == MFMailComposeResultSent {
print("sent")
} else if result == MFMailComposeResultFailed {
print("failed")
}
self.dismissViewControllerAnimated(true, completion: nil)
}
// 引数の内容でメールアプリを起動する
func sendMail(to:[String], cc:[String], bcc:[String], subj:String, msg: String){
if !MFMailComposeViewController.canSendMail() {
print("Mail services are not available")
return
}
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
var toRecipients:[String] = []
var ccRecipients:[String] = []
var bccRecipients:[String] = []
var subject:String
var messageBody:String
// TODO:ちゃんとチェックする事
if(to.count != 0){
for toMember in to {
toRecipients.append(toMember)
}
}
if(cc.count != 0){
for ccMember in cc {
ccRecipients.append(ccMember)
}
}
if(bcc.count != 0){
for bccMember in bcc {
bccRecipients.append(bccMember)
}
}
subject = subj
messageBody = msg
// Configure the fields of the interface.
/*
composeVC.setToRecipients(["送信先1", "送信先2"]
composeVC.setBccRecipients(["cc送信先"])
composeVC.setSubject("こんにちわ!")
composeVC.setMessageBody("Hello from California!", isHTML: false)
*/
if(toRecipients.count > 0){
composeVC.setToRecipients(toRecipients)
}
if(ccRecipients.count > 0){
composeVC.setCcRecipients(ccRecipients)
}
if(bccRecipients.count > 0){
composeVC.setBccRecipients(bccRecipients)
}
if(subject.characters.count > 0){
composeVC.setSubject(subject)
}
if(messageBody.characters.count > 0){
composeVC.setMessageBody(messageBody, isHTML:false)
}
// Present the view controller modally.
self.presentViewController(composeVC, animated: true, completion: nil)
}
}
登録:
投稿 (Atom)