2020年1月11日土曜日

HP B210a トラブル対策

昨年末は暖冬のせいか、給紙失敗は少なかった...
が、インク交換時から、縦筋汚れ(ヘッドが紙に当たっているような??)が出るようになった → "システムエラー"が出るようになり起動しなくなる まで行ったので対策を

電源を引っこ抜いてしばらく放置
 (30秒程度だとダメ、5分以上なら大丈夫そう)

その他
- プリンタヘッド右側のレバーでプリンタヘッドを外して端子を掃除すると治るとか
 (インクを水洗いしてメンテする人もいる模様) - "HP178 空気穴"で検索すると100均のcanon用インクでスポンジから補充できるみたい

もうちょっと使えそうかな


2019年2月16日土曜日

Travel keyboardとWindows10でトラックポイント効かない

Windows10にしてからドライバが勝手にアップデートされたりするせいか挙動が変わることが多いですが、トラベルキーボードのトラックポイントとUltraNaviが効かなくなったので対処法 (キーボードやマウスは効くんですけどねぇ)

とりあえす1803では以下で対処出来ました。

1. 設定 -> デバイス
 "IBM USB Travel Keyboard with UltraNav"と表示されている状態
2. ↑をスクロールさせると"デバイスとプリンター"があるので選択 (探しにくい...)
3. "IBM USB ..."を右クリック
4. "ハードウェア"タブに"Synaptics Composit USB HID device"が2つ存在するので以下の対応をそれぞれに対して行う
 プロパティ -> 設定の変更 -> "ドライバ"タブ -> ドライバーの更新 -> "コンピュータを参照して..." -> "コンピュータ上の利用可能なドライバ" -> "USB Composite Device"を選択


"4"で2個"Synaptics..."があるが、片方がトラックポイントで片方がUltraNaviの模様。

以前は別の対策を行ったのだけど、Windows Updateでドライバが更新されたりするとまた使えなくなるのでこの方法の方がお手軽な模様。
(自動のドライバ更新はちと勘弁してほしいところです...Lenovoの印象も悪いし先日もX220がログイン黒画現象でグラフィックドライバ削除で回復というのもありましたし)



 

2019年1月5日土曜日

HP 210aで年賀状を印刷する 2019年版(位置ずれ対応)

平成最後の年賀状となったが...印刷位置がズレる!!
今回はGIMPからの印刷ではなく、Windows10のエクスプローラから印刷することで回避できたので設定をメモ


0. あらかじめGIMPでpngとかでエクスポート
1.上記ファイルをエクスプローラで右クリック -> 印刷
2. 以下設定
 用紙サイズ はがき
 品質 高画質
 用紙の種類 インクジェット用官製はがき
 画像の部数 お好みで
 写真をフレームに合わせる チェック
3. オプションの以下をチェック
 印刷をシャープにする
 プリンターと互換性のあるオプションのみを表示する
4. 上記オプション -> プリンターのプロパティ
  給紙方法 フォトトレイ <テスト印刷時はA4で位置を検討
 用紙サイズ はがき < テスト時もこれでOK
 メディア インクジェット用官製はがき
 品質の設定 カスタム
5. さらに、上記から詳細設定
  グレースケール印刷 オフ < 他を選択すると白黒になるので注意
  フチなし印刷 フチあり印刷 < これでよい!!

※ レイアウトタブに"印刷の向き"があるが、最初は横になっている。縦にするとプレビューにも反映されるので、上記ハガキ印刷時は"縦"にしている

とりあえずコレでなんとかなった...


というわけで、HP210aも連続印刷でスジスジになるがまだ来年も使っているであろう??
(帰還後、追加印刷したらスジスジが出なくなっていたので時間をおけば治る感じ??)


2018年5月3日木曜日

VisualStudioCommunity2015でインストールが進まない

ASP.netのインストールでプログレスバーが進まない場合は、TiWorker.exeを落とすと解決しました。

1.タスクマネージャー
2.詳細
3.TiWorker.exeを右クリック
4.待機チェーンの分析
5.全部チェックしてプロセスの終了ボタン

上記操作でプログレスバーが先に進みます。

2018年4月8日日曜日

C#で正規表現

基本
. : 任意の1文字
+ : 直前の文字が文字が無いか1文字以上連続
* : 直前の文字が1文字以上連続
? : 直前の文字がないか、1文字あるか

^ : 行頭
$ : 行末

hoge[a-z]hoge : []内のアルファベットいずれか
hoge[^1-9]hoge : []内は数字以外

()はグループ化
(aaa|bbb) : aaaかbbbいずれか
hoge(eb)+ : hogeeb, hogeebeb, hogeebebeb など

\d : 数字

こちらのサイトがとても参考になります
http://hodade.com/seiki/page.php?chapter_3

一例ですが、以下からxxx-xxxxを抜き出したい場合 (xが数字)
123-4567 111111-6666 9990-999

こんな感じで
(\s|^)\d{3}-\d{4}\s
-行頭かスペースで始まり
- 数字3桁
- "-"を挟んで
- 数字4桁
- 空白で終わり
という意味になります


C#だと"Matches"を使うとマッチした内容がリストに追加されるので以下のようなコードが書けます

例: textbox_inの文字列をtextbox_regのパターンで検索する場合
---
using System.Windows.Forms;

using System.Text.RegularExpressions;

namespace RegEx01
{
    public partial class Form1 : Form
    {


        private void button_exe_Click(object sender, EventArgs e)

        {
            var text = textBox_in.Text;
            // var pattern = @"\s+";       // space
            var pattern = textBox_regPattern.Text;
            var regex = new Regex(pattern);
            textBox_out.Text = "";

            /*
            // 存在するかどうかを調べる
            var match = regex.IsMatch(text);

            textBox_out.Text = match.ToString();
            */


            // 検索結果を表示
            var matches = regex.Matches(text);
            foreach( var match in matches)
            {
                textBox_out.Text += match.ToString() + "\r\n";
            }

2018年2月24日土曜日

画像ファイルのノルム値を比較

- input側のtextboxにファイルをまとめてドラッグ&ドロップ
- "計算"ボタンでoutput側textboxにファイル名とノルム地をカンマ区切りで表示

using OpenCvSharp;

namespace PhotoDiffAnalyzer
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // 入力ファイルリスト
        List<string> sourceFileList = new List<string>();

        /// <summary>
        /// Ctrl-A対応
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox_DiffFiles_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.A)
                textBox_DiffFiles.SelectAll();
        }


        private void textBox_InputFiles_Enter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))

            {

                e.Effect = DragDropEffects.Copy;

            }
            else
            {

                e.Effect = DragDropEffects.None;

            }
        }

        private void textBox_InputFiles_Drop(object sender, DragEventArgs e)
        {
            // 操作対象のリストをクリアする
            sourceFileList.Clear();
            textBox_InputFiles.Text = "";


            // ファイルリスト更新
            string[] fileName = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            foreach (string file in fileName)
            {
                if (File.Exists(file))
                {
                    string ext = Path.GetExtension(file).ToUpper();
                    if (ext == ".JPG" || ext == ".BMP" || ext == ".PNG")
                    {
                        // 入力ファイルリストに追加
                        sourceFileList.Add(file);

                        // 表示更新
                        string dispStr = Path.GetFileName(file);
                        textBox_InputFiles.Text += dispStr + "\r\n";
                    }
                }
            }
        }

        private void button_Exec_Click(object sender, EventArgs e)
        {
            String outStr = "";

            foreach(String File in sourceFileList)
            {
                Mat image = new Mat(File);

                image.Canny(120, 80);
                double norm = Cv2.Norm(image);

                outStr = Path.GetFileName(File) + "," + norm.ToString() + "\r\n";

                textBox_DiffFiles.Text += outStr;
            }
        }
    }
}

2018年2月18日日曜日

ファイルをまとめてドラッグ&ドロップ

1. ファイルをまとめてテキストボックスにドラッグ&ドロップ
2. テキストボックスに↑のファイルを表示

という動作をさせます。

1. FormにTextBoxを配置
2. TextBoxのプロパティのAllowDropをtrueにする
3. 上記TextBoxに "DragEnger" , "DragDrop"イベントを追加
4. 上記イベントを実装
        private void textBoxPhotoFile_Enter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy;
            } else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        // 入力ファイルリスト
        List<string> sourceFileList = new List<string>();

        /// <summary>
        /// 操作対象の画像ファイルをドラッグ & ドロップした際にfileListとして登録する
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBoxPhotoFileDrop(object sender, DragEventArgs e)
        {
            // 操作対象のリストをクリアする
            sourceFileList.Clear();
            textBox_InputFile.Text = "";

            // ファイルリスト更新
            string[] fileName = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            foreach (string file in fileName)
            {
                if (File.Exists(file))
                {
                    string ext = Path.GetExtension(file).ToUpper();
                    if(ext == ".JPG")
                    {
                        // 入力ファイルリストに追加
                        sourceFileList.Add(file);

                        // 表示更新
                        string dispStr = Path.GetFileName(file);
                        textBox_InputFile.Text += dispStr + "\r\n";
                    }
                }
            }
        }

2018年1月21日日曜日

OneDriveでgitを使ってみる

remote repository にgit公式を使用すると、無料だと公開設定になってしまうそうなので、OneDriveを remote repositoryとして使ってみます。
(Visual Studioにもgitが入っているようですが、よく解らないのでtortoise gitを使います)

準備 (以下をinstall)
- git
- tortoise Git
- tortoise Git日本語language pack
順にinstallしてからExplorer右クリックでtortoise Git->設定を選択して"日本語"を選択する

リポジトリの生成作業
ローカルリポジトリを作成 -> リモートリポジトリを作成 と、それぞれを個別にやっても問題ないようですが、以下の手順でやってみました。
commitはローカルリポジトリで行い、pushはOneDriveにあるリモートリポジトリのファイルにおこなわれるので、ネットにつないであればOneDriveに同期される筈です。

OneDriveにリモート側リポジトリを生成
1. リポジトリとなるフォルダを作る
2. 上記フォルダ内で右クリック -> Gitここにリポジトリを生成
3. "Bareを生成"をチェックしてOK

ローカルリポジトリの生成
1. VisualStudioで生成したフォルダに移動
 (slnのある場所の一つ上)
2. 右クリック -> Gitここにリポジトリを生成
 ("Bareを生成"をチェックしない)
3. 登録するファイルを選択して"Gitコミット"
 ("1"のフォルダを指定して右クリックした場合はを以下に記載)
4. フォルダ下のファイルが表示されるがチェックボックスが外れているので必要なファイルをチェックする
 この辺は不要
  - bin下
  - obj下
  - *.suo
5. メッセージを記載して"コミット"ボタン押下

リモート側リポジトリと同期
1. ローカル側のフォルダトップを右クリックして"Git同期"を選択
2. "リモート"を選択
3. "URL:" に OneDriveフォルダ(C:\Users\****\OneDrive\ドキュメント\git\hogehoge)を記載。この時、"リモート"に"origin"という記載がされる
4. "新規に追加/保存"ボタンを押下

2018年1月7日日曜日

C#でExifを読む

C#のformアプリでexifを読みます。
"rational"の記載のあるものについては XX/YY というような表記をするようで、WORD1/WORD2 のようにすればよいようです。
以下は参照ボタンでOpenFileDialogにてパスを指定取得し、ボタンを押下することで街頭パスのExif情報をTextBoxに表示する例となります。

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.Drawing.Imaging;       // PropertyItems用

namespace ExifReader
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        // ボタンを押下するとOpenFileDialogによりファイルパスを取得する
        private void button1_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox_FileName.Text = openFileDialog1.FileName;
            }
        }

        // 表示ボタン押下でtextboxにExif情報を読んだ結果を表示する
        private void button2_Click(object sender, EventArgs e)
        {
            string filename = textBox_FileName.Text;
            Bitmap bmp = new Bitmap(filename);  // Exifのついたファイルを読み込む

            textBox_Output.Text = "";

            // 列挙してみる
            for (int i = 0; i < bmp.PropertyItems.Length; i++)
            {
                if (bmp.PropertyItems[i].Type == 2)
                {
                    string str = System.Text.Encoding.ASCII.GetString(bmp.PropertyItems[i].Value);
                    str = str.Trim(new char[] { '\0' });
                    textBox_Output.Text += string.Format("{0:X}:{1:d}:{2:s}\r\n",
                      bmp.PropertyItems[i].Id, bmp.PropertyItems[i].Type, str);
                }
                else {
                    textBox_Output.Text += string.Format("{0:X}:{1:d}:{2:d}\r\n",
                      bmp.PropertyItems[i].Id, bmp.PropertyItems[i].Type, bmp.PropertyItems[i].Len);
                }
            }

            // indexを使って直接取得してみる
            // ISOSpeedRatings
            int[] pils = bmp.PropertyIdList;

            int index = Array.IndexOf(pils, 0x8827);
            if(index > 0)
            {
                PropertyItem pi = bmp.PropertyItems[index];

                int iso = BitConverter.ToUInt16(pi.Value, 0);
                textBox_Output.Text += string.Format("iso: {0:d}\r\n", iso);        // iso: 100 と表示された
            }

            // https://msdn.microsoft.com/ja-jp/library/system.drawing.imaging.propertyitem.id(v=vs.110).aspx

            // FNumber
            index = Array.IndexOf(pils, 0x829d);
            if (index > 0)
            {
                PropertyItem pi = bmp.PropertyItems[index];

                // "rational"の解析は以下のようにする
                uint fn1 = BitConverter.ToUInt32(pi.Value, 0);
                uint fn2 = BitConverter.ToUInt32(pi.Value, 4);
                textBox_Output.Text += string.Format("Fnumber: {0:d}/{1:d}\r\n", fn1, fn2);        // Fnumber: 56/10
            }

            // ExposureTime
            index = Array.IndexOf(pils, 0x829a);
            if (index > 0)
            {
                PropertyItem pi = bmp.PropertyItems[index];
                uint exp1 = BitConverter.ToUInt32(pi.Value, 0);
                uint exp2 = BitConverter.ToUInt32(pi.Value, 4);
                textBox_Output.Text += string.Format("ExposureTime: {0:d}/{1:d}\r\n", exp1, exp2);        // exposuretime: 10/2000

            }
            // ExposureBiasValue
            index = Array.IndexOf(pils, 0x9204);
            if (index > 0)
            {
                PropertyItem pi = bmp.PropertyItems[index];
                int exp1 = BitConverter.ToInt32(pi.Value, 0);
                int exp2 = BitConverter.ToInt32(pi.Value, 4);
                textBox_Output.Text += string.Format("ExposureBiasValue: {0:d}/{1:d}\r\n", exp1, exp2); // ExposureBiasValue: 4/6
            }
      }
    }
}

2017年11月1日水曜日

アルバムから写真を取得して表示する (OpenCVでリサイズ)

ピッカーで選択した画像をリサイズして表示する

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年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!
 


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の表示されないアプリになっている事が確認できました。


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


2017年10月20日金曜日

bluetoothキーボードとマウスが不安定

Windows10を使用していますが、bluetooth keyboard / mouseがよく切断されて非常に使いづらい感じになっていました。

私の場合は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

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);
        }
    }
}

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);
        }
    }
}

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;
        }
    }
}

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;

        }
    }
}

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();
            }
            */
        }
    }
}