読者です 読者をやめる 読者になる 読者になる

(O+P)ut

IT系の記事やその他諸々,不定期で更新していきます(∵)

【Java】簡単モザイク生成

Java テクノロジー

これはなんのキャラクターでしょうか。
f:id:mtiit:20170314232445j:plain
どことなく、国民的アニメの主人公に色合いが似てる気がしませんか?

少し前に、モザイクをかけても人間はアニメキャラクターを見破ってしまう というのが話題になりました。
私も同じように、画像を配列と見た時に各行の平均の色を出力することで簡易モザイクを作成する遊びをしてみたのでここに共有します。

Javaでの画像取得は以下のように行います。BurreredImageのメソッドを用いて縦横のサイズも取得可能。

File f = new File("[入力画像のフルパス]");
BufferedImage read=ImageIO.read(f);
int w = read.getWidth();
int h = read.getHeight();

さて、画像の各画素を取り出して平均をとりたいんですが、
BufferedImageでは画素を取得するメソッドgetRGBを用いると、 R G B を8bitずつで表現する以下のような形が返り値となっています。
00000000 00000000 00000000 00000000
なので、R G B をそれぞれ取り出すために

public class Img{
 public static int r(int c){
  return c>>16&0xff;
 }
 public static int g(int c){
  return c>>8&0xff;
 }
 public static int b(int c){
  return c&0xff;
 }
 public static int rgb(int r,int g,int b){
  return 0xff000000 | r <<16 | g <<8 | b;
 }
}

といったクラスを用意しておくと便利ですね。
rgbは、各r,g,bを基に元の値を構成するメソッドです。

画像の各列の画素の平均値の画像を出力するコードは以下になります。

public class Main {
 public static void main(String[] args) throws IOException {
  File f = new File("[入力画像のフルパス]");
  BufferedImage read=ImageIO.read(f);
  int w = read.getWidth();
  int h = read.getHeight();
  BufferedImage write = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
  for(int y=0;y<h;y++){
   int r = 0;
   int g = 0;
   int b = 0;
   for(int x=0;x<w;x++){
    int c = read.getRGB(x,y);
    r = r + Img.r(c);
    g = g + Img.g(c);
    b = b + Img.b(c);
   }
   int n_r = r/h;
   int n_g = g/h;
   int n_b = b/h;
   for(int xx=0;xx<w;xx++){
    int rgb = Img.rgb(n_r, n_g, n_b);
    write.setRGB(xx, y, rgb);
   }
  }
  File f2 = new File("[出力先のフルパス]");
  ImageIO.write(write, "jpg", f2); //jpgで出力
 }
}

最初に見せたモザイク画像の元画像はこちらです。
f:id:mtiit:20170314234708p:plain
両側が黒くなっているのは、透明化している部分の画素が 0/0/0 で 黒と同じだからみたいです。
この辺は、改良の余地ありですね。以上です。

【Linux】wgetで桂離宮の参観可能日を取得する

テクノロジー Cygwin Linux

f:id:mtiit:20170213141405j:plain
この写真は、約1年前に桂離宮で私が撮ったものです。

日本には、桂離宮修学院離宮の二つの現存する離宮があります。*1
これらの参観は無料ですが、事前に予約を行うのが一般的です。詳しくは宮内庁のHP参照。
予約はWebからもでき、例えば桂離宮について見てみますと以下のようにWebで空き人数付参観可能日が確認できます。
f:id:mtiit:20170213142210p:plain
これらの情報を、Webサーバーからファイルをダウンロードするためのコマンドwgetを用いて取得してみたいと思います。

2017年2月現在、上のページのurlは

"https://sankan.kunaicho.go.jp/register/frame/4201?ym=[西暦4桁][月二桁]"

という命名規則となっています。

標準出力に出すためのオプション -O - を使いまして来月(201703)でwgetをしますと以下のようにエラーとなります。※環境によっては証明書の発行者が不明というエラーが先に出る場合があるかとは思いますが。*2

wget -O - https://sankan.kunaicho.go.jp/register/frame/4201?ym=201703<html><head><title>Request Rejected</title></head><body>The requested URL was rejected. Please consult with your administrator.<br><br>Your support ID is

The requested URL was rejected に関してですが、調べてみますと
"ユーザエージェントWgetを排除している可能性がある"
ということが分かりました。宮内庁のHPに関しては、他のページも同じエラーが起きました。悪戯対策なんですかね?
オプション -U "" を用いて明示的にユーザエージェントを空欄に変更してみると、

wget -O - -U "" https://sankan.kunaicho.go.jp/register/frame/4201?ym=201703<html>
  <head>
    <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <META http-equiv="Content-Style-Type" content="text/css">
...以下略

といった形で正規のhtmlを取得できました。

あとは、
日付情報↓

<TD width="20" align="center"><B>01</B></td>

参観可能人数情報↓

<img src="/images/false.gif">10:00(0人)

といったような構造になっておりましたので、以下のワンライナーで結果を取り出してみました。
読み方は、3月1日の15:30から2人空いている、といった感じです。

$ wget -O - -U "" https://sankan.kunaicho.go.jp/register/frame/4201?ym=201703 2>/dev/null | grep -B 10 '[1-9]人' | grep -e '[1-9]人' -e '<B>[0-9][0-9]</B>' | awk 'BEGIN{FS="[><]"}{print $5}'01
15:30(2)
02
10:00(1)
15:30(2)
03
09:00(4)
13:30(1)

ワンライナーに関して簡単に説明します。
大部分は 0人 ですので 0人以外のところを grep -B 10 '[1-9]人' で拾います。-Bオプションをつけることで、一致した行から前10行を同時に表示し、日付情報を拾い出しています。htmlを見ますと、日付~参加可能人数が10行毎に繰り返していたので今回はこのようにしています。そして、改めて日付と参加可能人数の情報をgrepで拾い出し、awkで欲しい箇所を抽出しています。今回は、< または > で区切るとどちらも5列目でしたので上のようにしました。

ちなみに、5月だと1日も空いてませんでした。。。
京都に立ち寄る予定がある方は、ぜひ事前に調べてみてください。

*1:修学院離宮にも行きました。どちらもぜひ一度は行ってみる価値ありです!

*2:接続先が信用できる場合では --no-check-certificate を追記ですれば簡易的に対応可能です。

【Linux】とりあえず2つだけ覚える、変数のパターンマッチ

テクノロジー Linux Cygwin

bashでは「%」や「#」を用いた変数のパターンマッチがありますが、最近使うことが増えてきたのでメモとして書いておきます。

紹介するのは、とりあえず2種類です。

${変数#パターン}
${変数%パターン}

[ファイル名][数字].[拡張子]のようなファイルを一気に処理したい場合等に使えたりして便利です。

紹介のために、以下のような4つのファイルを用意しました。

$ ls
file1.txt  file2.txt  file3.txt  file4.txt

4つのファイルをワンライナーでいじろうとすると以下の書き方が使えます。
fileで始まるファイルを変数xに格納して、echoで画面に表示しています。

$ for x in file*; do echo $x; done ⏎
file1.txt
file2.txt
file3.txt
file4.txt

さて、まずは ${変数#パターン} です。
ざっくり言えば "パターン部分を除いたファイル名の後半を取り出したい時" に使います。
正確に書けば、"変数の内容について、最初の部分とパターンがマッチした場合に、もっとも短く一致する部分を取り除いた残りの部分を返す" 役割が ${変数#パターン} にはあります。

以下を見ていただければイメージが掴めるかと思います。

$ for x in file*; do echo ${x#file}; done ⏎
1.txt
2.txt
3.txt
4.txt

これを応用すれば、file[数字].txt ではなく text[数字].txt としたい時などに使えます。

$ for x in file*; do mv $x text${x#file}; done ⏎
$ ls ⏎
text1.txt  text2.txt  text3.txt  text4.txt

次に、 ${変数%パターン} です。

こちらもざっくり言えば "パターン部分を除いたファイル名の前半を取り出したい時" に使います。
正確に書けば、"変数の内容について、最後の部分とパターンがマッチした場合に、もっとも短く一致する部分を取り除いた残りの部分を返す" 役割が ${変数%パターン} にはあります。

こちらも以下を見てください。※上の実行後に行っているので、ファイル名はtextから始まっています。

$ for x in text*; do echo ${x%.txt}; done ⏎
text1
text2
text3
text4

これを応用すれば、拡張子を一気に変えたい場合なんかに使えそうですね。

他にも、「##」や「%%」などもあるんですが、とりあえずは上の2個を覚えて必要あらば詳しく調べるのが良いかなーと思います。

【Cygwin】作業ログを自動で残す

テクノロジー Cygwin Linux

明けましておめでとうございます。今年は、少なくとも月1ペースで更新したいと考えています!

さて、Cygwinでちょこちょこと作業をすることが多いのですが script コマンドなるものを使えば、簡単に作業ログを残せることを知りました。
それを自動で行えるようにした際の備忘録です。

scriptコマンドの使い方は、ターミナルで script と打てば以下のようになるかと思います。

$ script
スクリプトを開始しました。ファイルは typescript です

ここから記録が ./typescript に始まり、終了する際は exit と打てば以下のように終了します。

$ exit
exit
スクリプトを終了しました。ファイルは typescript です

オプションや引数をつけることで、ファイルを上書きしたりファイル名を指定もできます。

問題は、これを起動時に自動で実行しようとする際です。
単純に .bashrc に

script

と書くとすごいことになります。以下が私の環境で実際に上記の記述を.bashrcに行い、起動した際の出力です...

スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です
スクリプトを開始しました。ファイルは typescript です

実はscriptコマンドは新たにシェルを立ち上げる挙動をするようですので、新たなシェルが立ち上がる→scriptコマンド実行→新たなシェルが... の無限ループになるみたいですね。

$ ps
      PID    PPID    TTY       STIME COMMAND
    13052       1    ?         01:08:49 /usr/bin/mintty
     6288    1936    pty0      01:08:56 /usr/bin/ps
     1936   13052    pty0      01:08:49 /usr/bin/bash

$ script
スクリプトを開始しました。ファイルは typescript です

$ ps
      PID    PPID   TTY      STIME COMMAND
     1288    5712  pty0      01:09:01 /usr/bin/script
    11180    4176  pty1      01:09:04 /usr/bin/ps
     5712    1936  pty0      01:09:01 /usr/bin/script
     4176    1288  pty1      01:09:02 /usr/bin/bash
    13052       1  ?         01:08:49 /usr/bin/mintty
     1936   13052  pty0      01:08:49 /usr/bin/bash

上がすごい分かりやすいと思います。pty1が立ち上がってカレントシェルが変更になります。

なので、今回は簡易的に現在のシェルの親プロセスが /usr/bin/mintty な場合にのみ script を動かすようにします。

autoscript.shというスクリプトを記述しました。*1

#!/bin/sh

ppcheck=`ps | grep $PPID | grep -v pty | awk '{print $8}'`
ttynum=`echo \`tty\` | awk '{print substr($0,(length($0)+1)-1,1)}'`
nowtime=`date +"%Y%m%d%H%M%S"`
filename="${nowtime}_${ttynum}"

if [[ ${ppcheck} = "/usr/bin/mintty" ]]; then
        script -f script_log/$filename
fi

簡単に説明しますと、ppcheckで現在のシェルの親プロセスのIDでプロセスを絞り込み、ttyが?となっている/usr/bin/minttyをppcheckとして取り込んでいます。
それを、現在のttyの最後の数字と現在の時刻とするファイル名でログをとる、という感じですね。こうしておけば、scriptで立ち上がったシェルの親プロセスは/usr/bin/minttyではなくなるので、ループは起きないといった感じです。ファイル名は、時刻だけだと同時にCygwinの窓を複数立ち上げるとやっかいかなーと思ったのでttyから値を持ってきてます。特に深い意味はありません...

これを起動時に実行するために .bashrc に以下のように記載します。

. ./autoscript.sh

カレントシェルで実行するよう記述しているのは、親プロセスが変わってしまうのを防ぐためです。

これでCygwinを立ち上げると

スクリプトを開始しました。ファイルは script_log/20170129011831_0 です

$ ls script_log/
20170129011831_0

とまぁ、こんな感じで機能しています。

とりあえずこれで運用してみて、挙動が怪しい場合にはまたその都度修正していこうと思います。
Cygwinをお使いの方で、同じようなことに興味がある方はご参考ください。

*1:直接.bashrcに記述してもいいですが、テストしやすかったのでそのままshファイルを起動するという構成にしています

マージソートの可視化

テクノロジー R アルゴリズム

ちょうと1年前くらいに
mti.hatenablog.com
といった記事を書いたんですが、そこでは選択ソートとバブルソートを可視化しました。

今回はマージソートの可視化を行います。使用するのも前回同様 R言語で。

マージソートとは、並べ替えたい配列を再帰的に分割していき、再び併合(マージ)していくことで並び替えを実現しようとするソートアルゴリズムです。

今回は配列をx、マージソート関数をf、基準値をpivotとし、基準値は配列xの平均値とします。

pivot=ave(x)[[1]]

そして、配列xの各値が基準(pivot)より大きいか小さいかで配列をleft,rightに分割

for(k in 1:length(x))
    {
      if(x[k] <= pivot)
      {    
        left <- append(left,x[k])
        count <- count + 1
      }
      else
      {
        right <- append(right,x[k])
      }
    }

分割したleft,rightを再起的にまたfにつっこむ流れですね。*1

分割の回数で上記のマージソートを可視化したものが以下になります。
f:id:mtiit:20161103103618g:plain
一秒毎に8回目までのソートの経過を可視化しました。選択ソートやバブルソートとは全く異なっていることが分かります。


おまけとして、pivotを

pivot_t=ave(x[1:2])[[1]]

とすればどうなるでしょう。直観的には、基準が前の二つの平均値となるので少し偏ったpivotで配列を分割していくことになりそうです。
同じく8回目までのソートの経過を可視化したものが以下になります。
f:id:mtiit:20161103104419g:plain
8回だけでは並べ替えきれていない感じがします。

以上、マージソートの可視化でした。*2

*1:countは配列の結合で用いる配列の引数としてfに渡してました

*2:分割と併合を繰り返したものの経過の可視化はマージソートWikipediaにも掲載されていましたのでご参考まで

【Java】APIリクエストでファイルを取得する

テクノロジー Java

APIリクエストってのはWeb APIのことですね.
HTTPをベースにしてデータをやり取りするので,一般的にはWebサイトへのアクセスを行うようにブラウザを用いて操作を行います.
例えば,今回の場合ではURLを入力してGETメソッドでアクセスする*1ことで,csvファイルをアクセスできるという状況が既にあります.

そんな中で例えば「日付でURLが分かれているファイルを一気に取得したい」であったり「csvファイルの特定の項を編集しながら保存したい」といったようなことをする必要もありますよね.自分はそのような状況だったので,Javaを使ってcsvファイルを取得する方法について記述します.*2

簡単なサンプルコードは以下になります.

URL url;
try {
	String url_s = "[アクセスするURL]";
	url = new URL(url_s);
	URLConnection conn;
	conn = url.openConnection();
	InputStream in = conn.getInputStream();
	BufferedReader br = new BufferedReader(new InputStreamReader(in));
	String line;
	while ((line = br.readLine()) != null) {
		System.out.println(line);
	}
	br.close();
} catch (MalformedURLException e) {
	e.printStackTrace();
}
catch (IOException e) {
	e.printStackTrace();
}

今回は一行ずつlineを標準出力していますが,必要に応じてファイルに保存します.
また,csvファイルの各項を取り出したいのなら

token = new StringTokenizer(line, ",");
while (token.hasMoreTokens())
{
   //処理を書く
         //token.nextToken()で項を順に取得
}

をline毎に行います.

備忘録でした!

*1:要は普通にWebブラウザを使ってアクセスする

*2:おそらく他の言語ならもっと簡単?

ソートの結果を可視化してみる

テクノロジー R アルゴリズム

Javaで学ぶデータ構造とアルゴリズム」という杉山行浩さんの本を読んでいたら,ソートの結果を可視化して図にしていた.これは面白い!と思ったので紹介させてもらうと同時に,僕も実際にソートした結果をGifにしてみました.

まずソートの可視化方法.例えば大きさ100の配列に,未ソートの状態で実数が入っている時に,配列のインデックスをx座標,その配列の値をy座標にとるというものでした.

つまり,例えば配列の大きさを1000として0~1で一様乱数を発生させると以下のようなグラフになります.
f:id:mtiit:20151003185351p:plain

これを初期状態としてソートを行っていく際の途中経過を表示していくのが,今回言っている「ソートの可視化」です.

百聞は一見に如かず.
選択ソートで可視化をしてみます.選択ソートとは,
例えば 大きさ5の配列
2 7 5 9 1
があった時に,
一番小さな 1 を 一番左に持ってきて,元あった2と入れ替える.
1 7 5 9 2
ここで一番左は整列済みなので,次は未整列な4つの中で一番小さい 2 を 一番左(整列しているところは除いて)と入れ替える
1 2 5 9 7
これを繰り返すと残りは
1 2 5 7 9
とソートが行われる,というアルゴリズムですね..

このアルゴリズムを用いて,0~1の一様分布に従った乱数1000個の配列に対して50個整列が終わる毎に出力したものをGifにしたのが下の画像です.







f:id:mtiit:20151003195514g:plain
分かりやすい...左側から整列していく様子が一目瞭然で分かる!

ついでにもう一つ.バブルソートではどのように整列が進むのでしょうか.
バブルソートとは,同じように大きさ5の配列
2 7 5 9 1
があった時に,一番右側の「1」から自分の左隣と比較して右側の方が小さければ値を交換していく.
上の例で言えば,9 と 1 を比較すると1の方が小さいので
2 7 5 1 9 となる.次は5と1の比較で
2 7 1 5 9
2 1 7 5 9
1 2 7 5 9
となって一番左側は整列済み,となる.同じようにまた 9と5を比較して,
1 2 7 5 9
1 2 5 7 9
1 2 5 7 9 となって1,2までが整列済み,というのを最後まで繰り返すアルゴリズムですね.

ではこれを同じようにGifにしてみると,どんな風に整列が進むか想像つきますかね?
正解は下の画像のようになりました.







f:id:mtiit:20151003195457g:plain
なるほど,バブルソートは隣あった数の比較を進めながら整列が進むので選択ソートよりかは途中段階においても緩やかなソートが行われていることが見て取れます.

このように,ソートのアルゴリズムを視覚的に表示させるのは,かなりいいアイデアだとは思う*1
上で紹介した本の中にはマージソートヒープソートも載っていて,「こんな整列の仕方してるのか!」と思った.

あと,今回はRでグラフを出したりしてたんですけど

plot(hoge)
dev.copy(png,file=filename)
dev.off()

でファイルネームでplotをpngファイルで保存できるんですね*2.便利でした.

*1:もちろんこの作者が考えついたとは思っていないが,僕はこの本で初めて知ったので!

*2:たしかpdfとか他の拡張子でもいける