それが僕には楽しかったんです。

僕と MySQL と時々 MariaDB

OpenCV+Pythonで顔にモザイク処理をする

顔にモザイク

最近はずっと画像処理の理論的な部分ばかり勉強していて、これといった成果物を出してないから
簡単に作れるものをとりあえず作ってみようっていうことで
今回は、OpenCV+Pythonで顔にモザイクをかけてみた

顔認識とかはよくわからないしそういったことはまだ勉強してないけど
とりあえず色々調べながら作ってみたけど、なにせpythonは基礎文法レベルでしか書けないから
今回はいろいろと苦労するところがあった

ただリスト形式で画像をあれこれいじれたのでなかなか楽しかった

仕組み

まず顔認識をしようとしても、どういう仕組みかわからない
というわけで画像処理速報さんで調べた結果、やりたいことに近いものがあり
そこで仕組みを説明していたので、自分なりにまとめてみる

実際にこれから紹介する順番でコードを書いている
今回はカスケード型分類器なるものを使った

1,対象画像を読み込む(変数は2つ用意しそれぞれ同じ画像)
2,顔認識用のカスケード型分類器を取得
3,カスケード型分類器で顔認識を行う
4,検出した情報に基づいて顔部分を切り取る
5,切り取った顔の部分にモザイク処理をほどこす
6,モザイク部分を結果出力用画像の一部に貼り付ける
7,結果を表示する

といった具合で顔認識以外はOpenCVで行えるかなり初歩的な処理を組み合わせることで実現できる
(その初歩的な処理を実装できなくて苦戦した)

コード

#coding:utf-8

import numpy as np
import cv2

#顔探索用のカスケード型分類器を取得
face_cascade = cv2.CascadeClassifier(haarcascade_frontalface_default.xmlのパスを渡す)

img = cv2.imread("Lenna.png")
result = cv2.imread("Lenna.png")

#読み込んだ画像をグレースケールに変換
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)

#分類器で顔を認識する
face = face_cascade.detectMultiScale(gray,1.3,5)

if 0 < len(face):

	print "get face"

	for (x,y,w,h) in face:
		
		#顔の部分だけ切り抜いてモザイク処理をする
		cut_img = img[y:y+h,x:x+w]
		cut_face = cut_img.shape[:2][::-1]
		#10分の1にする
		cut_img = cv2.resize(cut_img,(cut_face[0]/10, cut_face[0]/10))
		#画像を元のサイズに拡大
		cut_img = cv2.resize(cut_img,cut_face,interpolation = cv2.cv.CV_INTER_NN)
		
		#モザイク処理した部分を重ねる
		result[y:y+h,x:x+w] = cut_img

else:

	print "no face"


cv2.imshow("face mosaic",result)
#cv2.imwrite("output file name",result)
cv2.waitKey(0)
cv2.destroyAllWindows()

こんな具合で割と短いコードになった
注意すべきは7行目のカスケード型分類器の取得を行う部分で、ここで渡すのはカスケード分類器のファイル名を含めたパスであること
他のサイトではファイル名のみを渡していたりするがそれだと顔認識が正常に行われない上にエラーとしてもでてこない
つまりバグになるので注意

結果

いつもの例にならって使った画像は以下のLenna.png

f:id:RabbitFoot141:20160219022220p:plain

そしてこれが上のコードで出力したface_mosaic_Lenna.png

f:id:RabbitFoot141:20160219022301p:plain

python入門

はじめに

最近OpenCVpythonで扱うことが多くなったので一度しっかりと勉強してみる
今回は自分の備忘録として書くようなスタイルなので、ある程度プログラミング言語を他に扱えることを想定している
なので、ところどころ説明を省くので全くの初心者が見るべきではない
それと多々、javaと比較することがある(自分が一番得意としているから)

今回はpython2.7.6を使用していく

文法以前の基本的な事項

ここではまず基本的な事項、コメントやソースエンコードなどそういったことをまとめていく

ソースコードエンコーディング

これからpythonでコードを書いていく上で、対話型は使わずにソースファイルを作成しそれにソースコードを書いてくスタイルでやるので
ソースコードエンコーディングというものが必要になる

#coding:utf-8

をソースファイルの先頭に記述するだけでいい
これでコメントや文字列リテラルに日本語を使用できたりする
emacsでは-*-とやるみたいだが普段からvエディタはvimしか使わないのでそこは割愛する

コメント

ソースコードエンコーディングでも登場した「#」がコメントを表す
なのでpythonでコメントを各場合はこうなる

#これがコメント(coding:utf-8前提)

変数

まずは数値や文字列などをやる前に変数について
pythonで変数は

hello = "hello,world"
print hello  #print->hello,world

のように

変数名 = オブジェクト

という形をとり、作成とオブジェクトの代入がまとめて行われる
つまりこれまでのjavaやCといった言語のように宣言だけ先にしておくことはできない
それと関係して一度もオブジェクトが代入されていない変数を使用しようとすると「NameError」が発生する

また型推論なので変数にデータ型を指定することは必要ない

変数名の付け方はいつもどおり

オブジェクトの再代入はデータ型の制約がないため、全く別のオブジェクトでも代入可能つまり

number = 123
number = 3.14 #浮動小数点もok
number = "math"#極論これもok

更に変数を変数に代入することもいつもどおり可能
その他のプログラミング言語で採用してるもろもろのこともできる

ただし数値と文字列は演算することはできなく

num = 1
str = "hello"

print str+num

ということもできない

あと二項演算子も使用できる

数値

数値リテラルはいつもどおりなところが多いけど型推論な分多少注意が必要なのが
長整数と複素数

12000000000000000000000000000L#長整数
0+2j#複素数

長整数はざっくり言えばlongのことだから末尾にL,lが必要
だけど実際はこれすら推論されるから変数に代入するときは大して気にする必要がない

問題は複素数
実部虚部ともに宣言可能で虚部にはjをつける
また以下のように、実部虚部それぞれ取り出すことができる

c = 1 + 2j
print c.real
print c.imag


四則演算は少し今までの言語と違う部分がある
基本的に+,-,*,%,/が使えることに変わりはないが、**という累乗を表す演算子と//という小数点以下切り捨ての演算子があり
以下のように使用する

print 17.0//5 #print->3.0
print 5 ** 2 #print->25

累乗は

基数 ** 指数

という形になる

さっきの演算のところでもいったが文字列と数値は演算できない
そのため文字列を整数に変換することを考える
更には小数も整数に変換することを考える

まず前提として以下のようなことをすると

1 + "2"

「TypeError」が発生する
そこでint関数というものを使用しこうする

print 1 + int("2") #print -> 3

int関数は結構便利で基数を設定することもできる

print int("10",10) #基数10 print -> 10
print int("10",8) #基数8 print -> 8
print int("10",16) #基数16 print -> 16 

なので基数を16にした場合はA~Fまでのアルファベットも使えるが
10の時にそれらが含まれていると「ValueError」がでる

小数に対して使用された場合は0の方向に小数部が丸められる

文字列

リテラルはいつもどおりのダブルクォーテーション
ただしpythonはトリプルクォーテーションなるものがある

"""hello,world"""

これは複数行にわたって文字列が宣言でき、"""内の改行は\nに置き換えられる
更に便利なのはraw文字列というものがあって先頭にr,Rをつけると文字列内の\はそのまま扱われる

数値と文字では演算ができなかったが文字列同士では+で連結することができる

print "hello"+"world" #print -> helloworld

pythonには更に謎な機能があって
文字列を繰り返すことができる

"hello"などの文字列の後に * 回数 とすることでその文字列を繰り返すことができる

print "hello" * 3 #print -> hellohellohello

文字列の長さがlen()関数で行う

print len("hello") #print -> 5


数値と文字列は連結できないので文字列を整数にする方法を紹介した
今回はその逆で数値を文字列に変換する

それはstr関数によって行われ整数以外に小数も扱う

print 1 + str(2) #print -> 12

文字列オブジェクトはインデックスを指定することで文字を切り出すことができる

hello = "hello"
print hello[0] #print -> h

さらに文字だけでなく部分文字列も切り出すことができて
以下のようにする

hello = "hello"
print hello[1:3] #print -> el

条件分岐

いつもどおりのif文から
ただしいつもなら{}を使うがpythonはブロックがインデントで分けられるので
ちょっと勝手が違う
更にいうとelseifはelifでelseはいつもどおりelse

age = 18

if age < 20:
    print "未成年"
elif 20 <= age:
    print "成人"
else:
    print "エラー"

ここで注意したいのがtrue or false
pythonではTrue or Falseで先頭が大文字になる
また0は偽として扱われ、それ以外は真になる
空文字列も同様に偽となり空出ないなら真である
空のタプル、リスト、ディレクトリは偽であり真はない
Noneも同様

比較演算子はいつもどおりのものが揃っていてそれ以外はない
ちなみに==で文字列も評価できるがそれは値を比較しているだけであってオブジェクトを比較しているわけではない

なのでオブジェクトを比較するときはis,is notを使用する

また論理演算子は少し違って
&& -> and

-> or

! -> not
となる

リスト

pythonでは配列とjavaのCollectionのlistを足して2で割ったようなリストというものがある
宣言では{}ではなく[]を使用して以下のようにする

list = [1,2,3,4,5,6]

また含まれるオブジェクトは1種類に統一する必要はなく、数値と文字列のように混ざっててもいい
また更にいうとリストオブジェクトは別のリストオブジェクトを要素にできるから局所的に多次元配列のようにもできる

要素をインデックスで参照するときは

#list = [1,2,3,4,5,6]を仮定
print list[0] #print -> 1

となる、つまりいつもどおり

文字列でスライスを使って部分文字列を取得した時のように
リストに対してもそれは同様におこなえる
ただ説明してなかったのは、スライスで片方を省略したり、負の数が使えることである

#上記のlistを仮定
print list[3:] #print -> 4,5,6
print list[:3] #print -> 1,2,3
print list[1:-1] #print -> 2,3,4,5

要素の変更はいつもどおり行えるが
素数の違う部分配列をまとめて変更することも出来る

リストのサイズに関してはlenで取得できる

リストに要素を追加する場合はappend関数が使える
別のリストの要素を追加するときはextend関数を使う

list = [1]
list.append(2)
list.append(3)

list.extend([4,5,6])
print list #print -> 1,2,3,4,5,6

またリスト同士の連結は+で連結出来る
さらに文字列と同じようにリストを繰り返すことも出来る

listにインデックスを指定して要素を追加したい場合は
insert関数を使う

list = [1,2,3]
list.insert(1,4)#insert(インデックス,要素)
print list #print->1,4,2,3

リストの要素を削除するときはdelが使える

list = [1,2,3]
del list[0]
print list#print->2,3

指定インデックスの要素を削除するときはpop関数でインデックスを渡す
逆に指定の要素を持つ部分を削除するときはremove関数で引数に要素を渡す

スライスを使えばこれらのことが意外と簡単にできたりする

リスト[len(リスト):] = オブジェクト

で末尾に挿入ができる

また部分リストに対して[]を代入することでその要素を消すことができるが
スライスで部分リストを取得してない時には使えない


リストにある要素が存在するかどうかを確かめたいときはinを使う

list = [1,2,3,4,5]
if 2 in list:
    print "yes"

#print -> yes

逆に存在しない時はnot in

指定した要素が存在しそのインデックスを返すのはindex関数
これに引数としてインデックスを確かめたい要素を渡す
存在しないなら「ValueError」がでる

リストに含まれるある要素の個数を数えたいならcount関数に
カウントしたい要素を渡す

ソートはsortとreverseでjavaのCollectionsと同じ


連続した数値のリストを作成したいときはrange関数を使う

list = range(5)
print list #print -> 0,1,2,3,4

list2 = range(2,5)
print list2 #print -> 2,3,4 開始位置を宣言することができる

list3 = range(1,6,2)
print list3 #print 1 -> 1,3,5 stepを宣言できる

タプル

リストとほぼ同じことができるが宣言がすこし違う

tuple = (1,2,3,4,5)

と()でくくる
ただし要素がひとつだけの時は

tuple = (1,)

と最後に,をつける必要がある

要素の取得はリスト同様[]でインデックスを指定する
スライスとサイズの取得も同様、連結と繰り返しに関しても同じことが言える
tuple関数というものを使えばリストからタプルを生成できたりもする

辞書オブジェクト

これはjavaでいうMapとほぼおなじ

dict = {"java":1,"python",2}

のように{}で宣言する

キーに対応する値を取得したいなら[]でインデックスのようにキーを渡す
値の変更とサイズの取得もリストやタプルに同様

連結は

辞書オブジェクト.update(辞書オブジェクト)

キーの削除はdelが同じように使える
辞書オブジェクトに対してはpop関数は削除したキーに対応する値を返す

任意のキーを削除するならpopitem関数を使用
このとき選ばられるセットはランダムである

clearですべて削除できる


キーが含まれているかを確かめるのはin
キー in 辞書オブジェクト
not inも使える

inと同じ動作をするものでhas_key()もある

またkeys関数を実行することでキーをすべてリストとして取得できる
それは値にも使えて値をリストで取得したいときはvalues関数
(キー、値)のタプル形式ですべて取得するときはitems関数

ループ

まずはwhile文

while True:
     print "always true"

となる、つまりいつもどおり
ただしループを抜けた時の処理をelseで書ける

while True:
    print "always true"
else:
    print "error"

次にfor文

for i in [1,2,3,4,5,6]:
    print i

#print i -> 1,2,3,4,5,6

for文に対してもelseは適応できる
更に今はリストを渡していたがrange関数でわたすこともできる

画像処理におけるヒストグラム

はじめに

今回は画像処理をするとき(2値化などで)に使うヒストグラムというものについてまとめる

ヒストグラムとは

ヒストグラムとは画像処理以外の分野で使われることもあるが
画像処理の分野では、各濃度値に対してその濃度値を持った画素数を求めたもので、濃度ヒストグラム
または単純にヒストグラムという。

ヒストグラムは主に横軸が濃度値、縦軸に画素数をとったグラフで表現される

{\displaystyle
濃度値がq_i以上、q_i+\Delta q_i以上である画素数を
}
{\displaystyle
それぞれA(q_i)、A(q_i+\Delta q_i)とすると
}

{\displaystyle
濃度値q_iを持った画素数H(q_i)はH(q_i)=A(q_i)-A(q_i+\Delta q_i)となる
}
{\displaystyle
濃度レベル数nに対しH(0)〜H(n-1)によりヒストグラムを表現できる
}


ヒストグラムはその画像がどのような濃度値を持った画素から成り立っているかの情報をまとめたもので
画像処理において処理が容易なのもあり非常に有用な手段といえる

ヒストグラムの性質

ヒストグラムにはいくつかの性質がある

まずはヒストグラムは各画素の濃度値だけをとりあげているので、その画素の場所には関係しないグラフとなる
なのでその濃度値を持った画素がどれくらいあるかはわかってもその画素がどこにあるかまではわからない

つまり画像の持つ空間的特徴は考慮されずその情報はヒストグラム上では失われる


次に、ヒストグラムは同一の画像に対しては一意に、つまり一通りに定まるが
異なる画像であってもそれと同一のヒストグラムを持つことも可能性としてないわけではない

最後にヒストグラムは画像の各画素の濃度値を集めたのもなので
画像を分割してヒストグラムを求めた場合、それらの和が全体のヒストグラムと一致する

ヒストグラムの計算法

大きさMxN画素の濃度レベルがNGLの画像imgのヒストグラムを求め
配列hstに格納する方法でC言語ライクな擬似コードでしめす

また配列hstの初期値は各要素とも0であるとする

int i,j;
int img[N][M];
int hst[NGL];

for(i = 0; i < N; i++){
    for(j = 0; j < M; j++){
         hst[img[i][j]]++;
    }
}

濃度レベルが256で8bitだとすると
ヒストグラムは0〜255までの範囲となる

実用例

ヒストグラムの具体的な使い方は後述することにして
今回はpythonOpenCVを使ってヒストグラムを表示するものを紹介する

f:id:RabbitFoot141:20160206171235p:plain

例によりこのLenna.pngの画像を使う

結果
f:id:RabbitFoot141:20160208213332p:plain

#coding:utf-8

import cv2
import pylab as plt

img = cv2.imread("lenna256.png")
hist = cv2.calcHist([img],[0],None,[256],[0,256])
plt.plot(hist)
plt.xlim([0,256])
plt.show()

今回はカラーのままでやったがグレースケールにするとまた少し違って見える

ヒストグラム計算を自作してみる

ヒストグラムを求めること自体は結構簡単なので画像の入出力だけにOpenCVを使い
それ以外を自作するなんていうことも可能

#coding:utf-8

import numpy as np
import cv2

img = cv2.imread("lenna256.png")
#画像をグレースケールに変換
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)

#ヒストグラムを作成
histgram = [0]*256
for i in range(0,len(gray)):
	for j in range(0,len(gray[0])):
		histgram[gray[i][j]] += 1

画像処理における標本化と量子化

はじめに

画像処理でグレースケールと白黒について書いたがそれをもっと掘り下げようとすると

量子化についてのまとめが必要で、さらに量子化を説明しようとすると標本化まで説明しないと行けないので

今回はその両方を説明する

標本化

標本化とはざっくり言えば 空間的・時間的に連続した画像を離散的な点(標本点つまりは画素)の集合に変換すること

標本化によって横方向の画素数M、縦方向の画素数がNとなる場合画像の大きさはM×N画素となる
実際の標本化では各標本点の間隔をどのように選ぶかが問題となる
これに関しては対象画像がどの程度の濃淡を変化を含み、どれだけそれを忠実にとりこみたいかによるところが大きい

もっと細かく言うなら標本定理によって議論され、1次元標本定理が基本になる(らしい)

ここで一次元信号を
{ \displaystyle
g(t)
}
とするなら
g(t)に含まれる周波数がW以下である場合に限り
{ \displaystyle
T = 1/(2W)
}
間隔で標本化した標本値
{ \displaystyle
g(iT) (i = ... -1,0,1,2 ...)
}
を用いて式
{ \displaystyle
g(t) = \sum_{i=-∞}^{∞} g(iT)S(t-iT)
ただし
S(t)=sin(2πWt)/2πWt
}
により完全に復元できる


実際に写真などを取り込む場合(補足)

画像とは基本的に2次元平面上に連続的に分布した情報形態をとっているためコンピュータに取り込む際に一次元信号に直す必要があり走査というものが行われる

走査としては二次元平面を上から順番に一定間隔で水平方向にそってたどり濃淡値、つまり濃度値を取り出していくラスタ走査というのが一般的
そうして得られた一次元信号に対して一定間隔ごとにその値を求めていくことで離散的な点列を得ることができる

さらに動画の場合は時間軸でも標本化することが必要になり
時間軸で標本化、画面垂直、水平それぞれで標本化し3つの過程が必要となる

量子化


標本化によって画像は時間的、空間的に離散的に分布した画素に分解されるが
画素に関しては当然連続的な値になっている
画素の値としては、白〜灰〜黒の濃淡値が該当する
これは光の強さ、つまり明るさや輝度値の場合もある
この連続的な濃度値などを離散的な値に変換するのが量子化

今、量子化前の濃淡値を
{ \displaystyle
z
}
とするとき、濃淡値は連続的なため
{\displaystyle
z_i \leq z \leq z_i+1
}
となっているが、それを量子化すると
{\displaystyle
q_i
}
という整数値になる

このように得られた整数値は濃度値、グレーレベル、濃度レベルとよばれ
真の値zと濃度レベルqの差を量子化誤差という

量子化の方法

量子化レベル間隔が一定である場合

等間隔量子化と呼ばれるもっとも簡単な量子化方法で、標本値の濃度範囲を等間隔に分割する
画素の濃度値zが白から黒の範囲で一様に分布しているような画像に対して量子化誤差が最小になる
そのためこれは一様量子化、直線量子化とも言われる

量子化レベル間隔が一定でない場合

小さい濃度値に対してレベル間隔を細かくし
逆に大きい濃度値に対してはレベルを粗くする方法として、対数量子化がある

それ以外に画素の濃度値の確率密度関数を用いて
入力濃度値と量子化レベルとの平均2乗誤差を小さくする方法としてマックスの量子化がある

さらにはある範囲の濃度値が頻繁に生じ、その他がほとんど生じない場合はその範囲を細かく量子化
範囲外は粗い量子化する方法がある
これは量子化レベル数をそのままに量子化誤差を低減することが可能で漸減的な量子化と言われる

素数、量子レベル数と得られるデジタル画像との関係

ここでは画素数量子化レベルを変えるとどうなるか示す

素数を変えた場合

量子化レベルを256レベルで一定として
素数N*Nでどのように変化するか画像処理でよく見かけるlenna.pngで示す

256*256
f:id:RabbitFoot141:20160206171235p:plain

128*128
f:id:RabbitFoot141:20160206171256p:plain

64*64
f:id:RabbitFoot141:20160206171313p:plain

32*32
f:id:RabbitFoot141:20160206171341p:plain

256*256で十分な画質が得られるが、128,64,32と減っていくごとに一つの画素がブロック上になっているのが目立つ

量子化レベル数を変えた場合

素数を512^2で一定とし(元画像のサイズの関係で256にするの忘れてた)
量子化レベルを64,16,4,2と変化させると以下のようになる

64レベル
f:id:RabbitFoot141:20160206172555p:plain

16レベル
f:id:RabbitFoot141:20160206172622p:plain

4レベル
f:id:RabbitFoot141:20160206172636p:plain

2レベル
f:id:RabbitFoot141:20160206172647p:plain


64レベルではまだ元画像と大差ないがだんだん減らしていくと擬似輪郭(濃淡が本来滑らかに変化している部分で量子化のため濃淡に段差が生じ擬似的に輪郭が存在するように見える現象)が生じ、濃淡の細かい変化が失われ十分な画質を得ることができない

また最後に出した2レベルでは量子化の最も極端な場合で特にグレースケールの場合に2レベルにすることを2値化といい、こういった特殊な画像を2値画像という
後述にもだす予定だが、文字の識別などに使える


量子化レベルとしては一般的な画像では256レベル(8bit)
ただし医用画像など特殊な画像は256レベル以上で4096レベルなどが必要になる

取り扱う画像の画素数

画像を表現するために必要な画素数としては

その画像が空間的にどの程度細かい濃淡変化を含んでいるか
またどの程度細かい濃淡変化まで画像として表現する必要があるか、どの程度の解像度を必要とするかという点と

どの程度の範囲を画像として扱うかということに気をつける必要があり
対象の使用目的、種類に強く依存する

解像度が高くても対象の範囲が狭いならあまり画素数は大きくならないことに注意が必要である

グレースケールと白黒画像

はじめに

今回はグレースケールと白黒画像について少しまとめていく
あまり画像処理に興味がない人は、どっちも対して変わらんと思うだろうけど
実は明確な差がある

白黒画像

googleで白黒画像と検索すると以下のような画像が出てくるが
f:id:RabbitFoot141:20160206124520j:plain

これは正確には白黒画像ではない

コンピュータ画像処理において白黒画像とは白と黒の2値のみで表された画像なので灰色は含まれない
つまり、2値化した画像のことをいう

グレースケール

グレースケール画像というものは白黒の2値だけで表されていた画像に対して、灰色も含めて表す
具体的には白〜灰〜黒の連続した変化(濃度値)を8bitの0〜255の256レベルに量子化したもので
各濃度値に対応した濃淡の度合いを表示したもので、白黒画像に比べて豊かに画像を表現することができる


この表現方法にはいろいろあり
0を白、255を黒とする場合やその逆もある

対して白黒画像、つまり2値化した画像の場合は0を白、1を黒としたりする

OpenCVで画像の読み込みと表示、保存

画像の読み込みと表示、保存

OpenCVを使って画像処理をしようにも、まず対象の画像が読み込めないと何もできない

そして、いろいろやっていった結果の画像を見れるといいなというわけで

さらにいろいろやった結果を出力できたらなおいいというわけで、今回は全てやる

方法

まずcv2.imread("画像ファイル名")で画像を読み込んだものを変数に代入する
imreadの第二引数を0にするとグレースケールで読み込める

画像を表示するにはimshowを使い
cv2.imshow("ウィンドウ名",画像を読み込んだ変数)とする

#coding:utf-8

import numpy
import cv2


img = cv2.imread("Lenna.png")
img2 = cv2.imread("Lenna.png",0)#グレースケールで読み込み

cv2.imshow("color",img)
cv2.imshow("gray",img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

waitKeyではキーボードからの入力待受で引数のミリ秒だけ入力を待ち受けてその後次の処理に移る

destroyAllWindows()では現在表示中のhighGUIの画像表示窓を全て破棄する

これで画像の表示と読み込みができるようになった


次に画像の保存
今回はカラー画像をグレースケールで読み込んでそれを出力する

画像の出力は簡単で
cv2.imwrite("出力画像ファイル名",画像ファイルを読み込んだ変数)
でいいので

#coding:utf-8

import numpy
import cv2

img = cv2.imread("Lenna.png",0)#グレースケールで読み込み
cv2.imwrite("LennaG.png",img)

これで画像の読み込み、表示、保存ができるようになった

PythonでOpenCVを使えるようにする

環境

Ubuntu 14.04
Python 2.7.4

方法

まずは例にならって環境を最新にする

sudo apt-get update
sudo apt-get upgrade

これで必要なパッケージをインストールするだけ

sudo apt-get install libopencv-dev
sudo apt-get install python-opencv

numpyが必要なので入っていない場合はそれもインストール


それでちょっとテスト

#codeing:utf-8

import numpy as np
import cv2

img = cv2.imread("ここにファイル名");
cv2.imshow("作成するウィンドウ名(なんでもいい)",img)
cv2.waitKey()

ついでにヒストグラムの時に便利なライブラリもまとめていれておく

sudo apt-get install python python-dev
sudo apt-get install python-numpy python-scipy python-matplotlib

ここでさらにヒストグラムを出してみる

#coding:utf-8

import cv2
import pylab as plt #グラフ可視化

im = cv2.imread("ファイル名")
hist = cv2.calcHist([im],[0],None,[256],[0,256])
plt.plot(hist)
plt.xlim([0,256])
plt.show()

これでpythonOpenCVを扱う準備ができた