画像形式PNGへの変換(C++で簡単に)

あれ?ここは?電脳意識の中か?。。(ザザッ、、)やあ、俺だよ。
任意の画像形式をPNG形式に変換するツールをC++でお手軽に作りたくなったので、OpenCVで何も考えずに、imreadとimwriteを使って作ったのでそのための最低限のソースを以下にメモってみる。まさにPowered By OpenCV
OpenCV 3.4.1使用)
(以下、ヘッダーやライブラリのリンクは、あなたのOpenCV環境による話ですので臨機応変に対応ください。)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <shlwapi.h>
#include "opencv2/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#pragma comment(lib, "shlwapi.lib")
#ifdef _DEBUG
#define CV_EXT "d.lib"
#else
#define CV_EXT ".lib"
#endif
#pragma comment(lib, "opencv_core340" CV_EXT)
#pragma comment(lib, "opencv_highgui340" CV_EXT)
#pragma comment(lib, "opencv_imgcodecs340" CV_EXT)

using namespace std;

int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    cout << "usage a.exe <image_file_path>" << endl;
    return 0;
  }
  if (PathFileExists(argv[1])==FALSE)
  {
    cout << "could not open file. abort.\n" << endl;
    return 0;
  }
  cv::Mat image;
  // 任意形式の画像を読み込みます。
  image = cv::imread(argv[1], CV_LOAD_IMAGE_COLOR);
  //cv::imshow("hi", image);
  char fn[234];//←まここはお好みで(笑)
  strcpy(fn, argv[1]);
  *PathFindExtension(fn) = '\0';
  strcat(fn, ".png");
  // 元画像と同じ場所にPNG形式として出力します。
  cv::imwrite(fn, image);
  return 0;
}

PNGへの変換目的のためだけに、作ってるプログラムをOpenCV依存アプリにするのも嫌だったので、こういう別個独立お簡単ツールとして作ってみました。
まこれで作ったEXEを起動するBATを書いて、そのショートカットに、変換したい画像をドロップするもよし、そのショートカット(.lnkファイル)を、
for %%i 文の中で呼び出して、全画像ファイル一括バッチ変換!みたいなことしてもいいし。夢も広がるってもんだ。

パス表記のダブルクォーテーション問題は、BATファイル内で解決しよう。

やあ子供たち。物理ベースドレンダリングなんかに夢中になってる場合じゃないぞ、今はその時間AIの勉強に使った方が自分への投資になるぞ。なんて思ってるのはおじさんだけかも知れないが。。(どっちに行ってもNVIDIAなのでどっちでもいいという噂もあるが)さて本題に入ろう。
Windowsでは、パスの中にスペースがある場合などに対応するために、パス表記全体を、ダブルクォーテーションで囲むということをしますが、そうやって環境変数などに定義された、パス文字列を、いざプログラムに読み込む際には、さてこのパス文字列が、ダブルクォーテーションつきなのか否かを判断して、前者の場合には、文字列の最初と最後に現れるこのダブルクォーテーション記号を切り落としてやる必要があります。そこで登場するのが、まさかのWin32API、「PathUnquoteSpacesA()」だ。

// image_pathを取得
const char* image_path = getenv(image_env);
// image_pathの両端にあるダブルクォーテーションを削除。
// (image_pathの内容が更新される)
PathUnquoteSpacesA(image_path);

しかし、こんなものを導入しなくてもいい話があるのだ。それは、もうBATファイルの中の時点で、ダブルクォーテーションを予め取っ払ってやればよい。BATファイルの中で、置換構文を使えばよい。

set XX=%X:"=%

そう、つまりこれは、文字列Xの中の、ダブルクォーテーションを全て削除した文字列をXXに返すというものだ。具体的には以下のような使い方だ。

@echo off

set A="patty cake"
set B=patty cake
set C="bakers""" m""an"
set D="bake me a cake as fast as you can"

set X=%A% %B% %C% %D%
set XX=%X:"=%

echo %XX%
pause

上記を単独の、a.batとでもして、実行してみれば結果は以下のようになる。

patty cake patty cake bakers man bake me a cake as fast as you can

冒頭のWin32APIは、文字列の両端にあるダブルクォーテーションしか削除してくれないのだろうか。そんなことは確認してないが、もうそんなことはどっちでもよくて、このダブルクォーテーションの文化は煩わしいので、極力BAT側で、問題をとっぱらってしまい、あとはダブルクォーテーションなんて想定してないプログラムに流し込むだけ、つまり上記の例でいえば、%XX%を、そのプログラムの引数にして呼び出すようにすればおしまいだ、こうして楽をしよう、この厄介なダブルクォーテーション問題をこのようにして乗り切ってやろうという趣旨の記事でした。
EXEは変えられないけどBATファイルなら末端でいくらでも編集できるからね。今日はこんなところで。チャオ!

胃カメラの検査したよ

やあ子供たち。おじさんは今回初めて胃カメラの検査をしたので今日はそのメモだよ。
ま発端はバリウムの検査でポリープと疑われる影があるから胃カメラで再検査したらどうよみたいな、よくあるパターンなのかなこれ。今回は近場の評判のよさそうなお医者さんを探してそこでやってもらうことにした。
始まる前はやっぱりいろんな想像をして、「何でも飲み込んでやる」くらいの気持ちでいかないとだめなんだろうなとか、やっぱり途中で咳き込んだりしてパニックみたいになってしまうのだろうかとか。とくに診察台の上で待ってる直前の時なんかはどうしても体が硬くなってしまっていることに気付いたから、お腹や腰のあたりから力を抜く練習をひたすらしたり。
やっぱり一番気になっていたのがチューブの太さなんだけど、今回検査室に入って目に入ってきたのは、直径5〜7ミリくらいのやつだった。1センチくらいのやつを想像していたので、あーこれなら大丈夫かなって一瞬思ったんだ。
今回は眠るとか、そういう本格的な麻酔はなしでお願いしたんだけどそれでも最低限の麻酔はやるみたいでそれは注射とかではなくて、ゼリーを口から入れられてのどのあたりに3分くらい置いてくださいというのをやった後、(このゼリーは若干苦かったがそこそこの味がつけられていた)スプレーを2回くらい喉の奥に吹き付けられるだけのことなんだけど、この麻酔が結構効いて、喉や食堂のあたりが痺れたような感じになってきたんだ。後で思うとこの簡易麻酔が随分といい仕事をしていたのではないかと思う。
するとついに先生が入ってきて、「よろしくお願いします」。わー先生きちゃったよーなんて思ったんだけど、この先生が本当に安心させてくれる言葉をたくさん話してくれるものだから本当にそれも助かったんだけどね。
そこからはよくみるあのカメラのチューブを噛まないようにするためのマウスピースみたいのをつけて、「はい息をとめて」言われたと思ったら、「はいはいもう入っちゃったよ、あとはぼーっとしてるだけでいいからね」。麻酔のおかげか、喉のところにチューブが当たる感覚しかなくてそこから下の食堂の感覚とかは全くもうわからない。ま途中2、3回オエッとなることもあったけど、先生が「もう8割9割終わりました」と言ったかと思うと「はい抜いていくよー、また息をとめておいて」で、全ては終わり。
というわけで、眠らされてやるのもあるみたいだけど、おじさんは次回やることがあったとしても、今回のやつだったら全然大丈夫かなって思ったっていう話。
じゃ、今日はそんなところだ。これから「ハンソロ」の2回目を見に行くから。チャオ!

Windows10(1803)でフォルダオプション設定やコントロールパネル、共用スタートアップを出すやり方

やあ子供たち。Windowsで設定作業を行う場合にはいくつかの決まりきったフォルダや設定画面にアクセスしなくてはならないが、Windows10になってまたまたそれらの出し方やアクセス方法が厄介になってるのでおじさんはここにまとめてメモしておくことにしたよ自分のためにな。
●Windows10(1803)でフォルダオプション設定の出し方
Windows10になってもフォルダオプションを設定したい場合は、当然発生するわけで。たとえば、導入したばかりのマシンで、拡張子が見えなくなっていたり、隠れファイルやフォルダを表示しない初期設定のままになっている場合がそうだね。
開発者として当然拡張子は見えてほしいし、隠れフォルダもちゃんと見えてほしいと思うのは当然のことだよな。そんなときには必ずフォルダオプションの設定をする必要に迫られることになるわけだが、Win10の場合は、ちょっと今までの場所とは違うところに行かないとフォルダオプションは見れない感じになっているぞ。
それは、エクスプローラの左上にある、「ファイル」メニューの中の、「フォルダーと検索のオプションの変更」というのをクリックすることだ。これでフォルダオプションの画面に行けるぞ。
例によって、ひとたびフォルダオプションのダイヤログが開かれてしまえば、あとは旧来のWindowsと同じ作業をやるだけだ。
●Windows10(1803)でコントロールパネルの出し方
簡単だよ、画面左下のCortanaのところに、「control」と打ち込んでみよう。次にまた開くときはもっと楽だぞ。「con」と3文字だけ打ち込んでみるだけで、コントロールパネルが出たよ。一度閉じて、またまた開きたくなったときはもっと楽になってるぞ。Cortanaのところに、「c」と一文字打ち込むだけで、、あら不思議!(おじさんの環境だけかな。ちょっと試してみてくれよな)
●Windows10(1803)で、共用スタートアップフォルダを出す方法
これは簡単。「ファイル名を指定して実行」から、「shell:common startup」と打てばいいぞ。その他。「shell:common desktop」などは覚えておくと便利かも知れないぜ。
ではまた今日はこんなところで。チャオ!

PHPでheaderエラー

やあ子供たち。PHPをお勉強していて、ページ遷移トライだよとか言って、実行してみると、

Warning: Cannot modify header information - headers already sent by
(output started at /some/file.php:1) in /some/file.php on line xx

こんなエラーが出てどうしても理由がわからないなんてことでめげそうになってやしないか。そんなときはあれだ、エディタの文字コード保存オプションが、ただのUTF-8になっていたりしやしないか。それじゃだめで、UTF-8N とかにしないとだめなことがあったので、ここにメモしておくぞ。(自分用にな)
チャオ!

TensorFlow::Estimatorでモデル改変の際はCPの削除を忘れるな!

やあ子供たち。TensorFlowやってるか。みんな使ってるとかいっても独学はなかなか簡単ではないなーというのがおじさんの感想なんだけど、まー面白いと思えるところまではきたのでなんとか頑張っているよ。

さてさて、最近おじさんは自作のとある機械学習サンプルを実装していて気づいたのだけど、でね、これはEstimatorを使っている話ですので注意して下さい。まー今日のこれタイトルなー。わかってる人にはもう当たり前なんだと思うんだけどおじさんみたく周りに誰も聞ける人がいなくて、独学で、ググりだけできてますみたいな感じだとほんと苦労してたどり着いた内容なんだよね。さて本題に入ろう。
Estimatorを使っていて、train()とかの引数で指定する、ニューラルネットの構造を作成するためのユーザー指定関数、(cnn_mnist.pyの本家サンプルではmodel_fnなどとされているやつ)の中で、まさにdenseだとか、conv2dだとか使ってニューラルネットの構造を記述する場所があると思うんだが、そこの構成を変えると、以下のようなエラーが出てきて、

InvalidArgumentError (see above for traceback): 
Assign requires shapes of both tensors to match. 
lhs shape= [5,7] rhs shape= [5,3]

ま、こうなるとコード変えたのがいかんかったのかなー、もとの構成に戻すと大丈夫だしなー、でも構成変えようとするとエラー出るなー。まだまだ俺も勉強が足りないな、いやしかし間違ってないはず、、なんてね。こんなの真面目に考えてたらほんといろいろ調べちゃうし、勉強しちゃうし、それはそれでいんだろうけど、エラーはなくならなくて、気力が尽きそうになってしまうんですよ。
でまあ、もちろんね、このエラーの文字列で検索すれば、同じことで困ってる質問と回答があるにはあるんだけど、なかなかそうなって理解するまで時間かかっちゃったので、メモしておくぞ。

これはね、このエラーはどういうことかというとここに書いてある話なんですね。
そう。Estimatorというものは、そのコンストラクター呼ぶときに、モデル情報のログを書き出すパスを指定するようになっていて、これがログというか、チェックポイントと呼ばれるものがここに書き出されるわけで、これが実は、普通ログの出力先なんてまずはどうでもいいが適当に出力させておけって感じなのだが、そうじゃないと。どうでもよくないし適当ではうまく動かないのだと。なぜならこれが相当無視できない感じの情報になっていて。
Estimatorの、train(),evaluate(),predict()を使う限り、これはそのプログラムで実行された学習結果とかが、必ずここに出力される感じになっており、しかも、ここが一番タチの悪い点なのだが、次回にこれら関数がよばれるときは、まずはここからこれまでの学習結果をロードしてきてくれちゃうらしいのです!なので、上述のエラーは、「これまでと、そもそもニューラルネットの形が違います」といってきているのは、このチェックポイントなるものから読み込んだニューラルネット構造との不整合を言ってきているというわけだったようです。
んー、まわかってしまえばそれだけのことで、これがいやだったら、一つ方法としては、プログラムの実行の都度、事前にそのログ出力先のフォルダを削除してから、実行する、ということをやればいいようだね。
っていうことがあったりで、どうも、Estimatorなんてのは使わなくてもよさそうなアプローチがありそうなんで、そういうとこを次は勉強してみっかな、という気には前からなってたのだけど、その思いをさらに強くしてくれる今回の一件だったんだなと思ってます。
では今日はこの辺で。チャオ!


___________________

pythonのOpenCVでfloodFillを使ってみたよ


やあ子供たち。花粉症に悩まされていないか。くしゃみばかりしてないで、マスクをするとか、薬を飲むとか、ちゃんとやっているか対策。
今日はOpenCVの連続領域塗りつぶし用関数floodFill()のお話だよ。floodFill()というのは、昔のPC88のPaint()文なんかに似た動作をする、塗りつぶし機能だよ。同関数は本来のC++実装では、マスクというものを指定するバージョンと指定しなくてもいいバージョンとがあるのだけれども、どうやら現状の python による実装では、マスク指定のものしかラップされてないみたいなので、マスクの意味もちゃんと理解して、これを作成し、引数として渡してあげないと、floodFill()は使えないぞ。今日の流れとしては、MatPlotLibで作成した上のような画像内の指定箇所からfloodFill処理を起動することを考えていくよ。
このマスクっていうのはどういう意味というかまどう準備すればいいのかというと、本来塗りつぶしたい画像があって、それとは別に、マスク画像というものを作ってあげるんだね。しかもこのマスク画像は本来の画像のサイズに対し、上下左右とも、+1ピクセル太らせてあげなくてはならないんだ。マスク画像というのは、いわば垣根だね。塗りつぶしには、塗りつぶしを開始する画像上の位置を指定してあげるのだけれど、この開始点からh始めてどんどん領域が広がっていくが、対応するマスク画像上の位置に、白ピクセルがあれば、それは垣根なのでそれ以上塗りつぶしにいかないということがあるんだね。
さてさて、floodFillの最小限サンプルとして以下コードを公開するぞ。

import numpy as np
import matplotlib.pyplot as plt
import cv2

#必ずUTF-8にて保存のこと

def main():

  # *** 閉曲線の作成 *** 
  x=[]
  y=[]
  for itht in range(361):
    tht = itht*np.pi/180.0
    num_polygon = 7
    r = 2+1*np.sin(tht*num_polygon)
    x.append(r*np.cos(tht))
    y.append(r*np.sin(tht))
  # *** プロット処理 *** 
  plt.figure( figsize=(3,3) )
  plt.plot( x, y )
  # *** プロット画像の保存 ***
  plt.savefig("tak.png")
  # *** 画像をOpenCV画像としてロード *** 
  img = cv2.imread("tak.png")
  # *** エッジ検出画像をマスク画像として用意 ***
  mask = cv2.Canny(img, 100, 200) 
  # *** マスク画像の拡張。(画像の上下左右に1ラインずつ拡張)
  mask = cv2.copyMakeBorder(mask, 1, 1, 1, 1, 
    cv2.BORDER_REPLICATE)
  # *** 領域塗りつぶしと結果の表示
  cv2.floodFill( img, mask, (120,120), (0,255,255))
  sz = img.shape[:2]
  cv2.floodFill( img, mask, (int(sz[0]/2), int(sz[1]/2)), (0,255,0))
  cv2.imshow("canny",mask)
  cv2.imshow("flood",img)
  cv2.waitKey()

if __name__=='__main__':
  main()

ま途中画像ファイルを介する必要があるのか?というところだけど、まメモリ上でやりとりすればわざわざファイルに書き出さなくてもいんじゃねみたいは方法がわかる人がいれば教えてくれ。今回はおじさんはファイルを介すという安直なソリューションを選んだわけだけどな。
さてさて、このコードがいろいろ備忘録になるわけですよ。matplotlibと、OpenCV、それぞれの勉強になるよな。例えばこの中には、
(MATPLOTLIB)

  • 曲線形状の作成とプロットのやり方
  • 実際のプロット処理
  • 画像の保存(MATPLOTLIB)

(OPENCV)

  • 画像のロード
  • エッジ抽出(CANNY)
  • 画像を太らせる方法(cv2.copyMakdBorder)
  • 実際の領域塗りつぶし実行と結果画像の表示

といった具合にだ。だから記事にしたんだよ。おじさん自分のためにな。実行結果の画面が以下のような感じだよ。

はい、ちゃんとこの葉っぱのような形状の内側を緑で、そして、その外側を黄色で塗り分けることができたね。
さて今日はもうこの辺で。チャオ!