Python :  Dataframeの検索して読み込み及び書き換え

 Pythonのpandasを用いた

dataframeからのデータの読み込み及び検索した値での書き込みについてです。

 

pandasは最初に考えた人が動物のパンダが好きだったのかな?と思っていたのですが、

「panel - data - s」からきているようです。

多次元の構造化されたデータセットという意味のようです。

なんとなくパンダも好きだったような気はしますけどね。

関係ないですが、動物のパンダですが、中国語だと熊猫(Xiong Mao)と言います。

パンダと聞くと発音的には胖的(Pang de)という風に私には聞こえます。

この胖的という意味は肥ったとかそういう意味なので、

むか~し、イギリス人あたりが中国でパンダを見たときに、あれ太っているというのを

聞いてパンダって名前になったのかなーなんて思っています。

 

さて、今回はcsvファイルに書き込み、

それを検索して書き込みという方法を取ります。 

 

今回はPandasを使うので、インポートします。

import pandas as pd

 

ファイルの作成は下記です。

 import pandas as pd

#csvファイルを作成
f = open('pandas.csv','w',encoding='utf-8')
            
#作成するCSVの列名
f.write('line'+','+'column'+','+'a'+','+'b'+'\n')

#書き込むデータ
list_line =[1,2,3,4,5,6]
list_column = ['a','b','c','d','e','f']
list_a = [10,20,30,40,50,60]
list_b =  [100,200,300,400,500,600]

#dataを書き込む
for i in range(0 , 6):
    f.write(str(list_line[i]) + ',')
    f.write(str(list_column[i]) + ',')
    f.write(str(list_a[i]) + ',')
    f.write(str(list_b[i]) + '\n')
    i = i + 1
#dataframeを閉じる       
f.close()

こんな感じのファイルになります。

 

f:id:Kangkang1981:20210118221709p:plain

CSVファイルの作成については以前下記で説明したので、

こちらを参照ください。

kangkang1981.hatenablog.com

 

検索するファイルができたら、

まず読み込みます。

f1 = pd.read_csv('pandas.csv')

次に検索ワードを設定します。

ここを変えれば違うものを抽出できます。

line_i = 2

column_i = 'b'

これは蛇足ですが、行をすべて取得する場合は下記のように取得します。

f1_01 = f1[(f1['line'] == line_i) & (f1['column'] == column_i)]

 

本題ですが、indexを取得します。

データを抜くときにindex、即ち何行目にあるか?というのがわかると

後は、その列の名前、今回だと'a'とか'b'を指定すれば抜き出せます

indexは下のdatafurameの赤丸の部分です。

f:id:Kangkang1981:20210118221929p:plain

 

上の行すべてと似たようなものですが、indexは下記のように取得します。

f1_02 = f1.index[(f1['line'] == line_i) & (f1['column'] == column_i)]

今回はlineとcolumnという2種類から検索をかけているので、&を使っています。

一つだけの場合は一つだけにしてください。

 

一致しているかの確認をします。

手っ取り早いのはlenを使って存在するか(1)しないか(0)を見ます。

print(len(f1_02))

ここからif文で一致する場合としない場合の処理です。

if len(f1_02) == 1:

まず一致の場合

 

インデックスNoをindex_iに代入

index_i = f1_02[0]

 

結果の表示と一致したというコメント
print(f1.at[index_i,'a'])
print(f1.at[index_i,'b'])

print('一致しました')

 

単に抜き出す場合はこのようにすれば抽出できます。

result_a = f1.at[index_i,'a']


結果を書き換える場合はこのようにします。

今回は適当に15,20に書き換えます。
f1.at[index_i,'a'] = 15
f1.at[index_i,'b'] = 20

結果を表示します。

print(f1)

こんな感じのcsvファイルになります。

f:id:Kangkang1981:20210118222944p:plain

一致しなかった場合の処理です。
else:
print('一致しませんでした')

 

最後にデータの上書きです。

名前を変えて保存したい場合は、別のファイル名にしてください。

f1.to_csv("pandas.csv", index=False)

 

今回はデータ量が少ないので、csvにしましたが、

数千ぐらいのデータならcsvでも構いませんが、

数万になる場合は、csvはやめておいたほうがよいです。

バイナリファイルとかほかのファイル形式でやることをお勧めします。

ただ、ソフト起動じのパラメータの保存ぐらいだとcsvのほうが直接ファイルも

確認できるのでお手軽です。

 

プログラムの詳細は下記です。

import pandas as pd

#csvファイルを作成
f = open('pandas.csv','w',encoding='utf-8')
            
#作成するCSVの列名
f.write('line'+','+'column'+','+'a'+','+'b'+'\n')

#書き込むデータ
list_line =[1,2,3,4,5,6]
list_column = ['a','b','c','d','e','f']
list_a = [10,20,30,40,50,60]
list_b =  [100,200,300,400,500,600]

#dataを書き込む
for i in range(0 , 6):
    f.write(str(list_line[i]) + ',')
    f.write(str(list_column[i]) + ',')
    f.write(str(list_a[i]) + ',')
    f.write(str(list_b[i]) + '\n')
    i = i + 1
#dataframeを閉じる       
f.close()

#ファイルを読み込む
f1 = pd.read_csv('pandas.csv')            

#検索ワードを設定 line_i = 2 column_i = 'b' #一致する行をすべて取得 ※今回のプログラムとしてはなくてもよい f1_01 = f1[(f1['line'] == line_i) & (f1['column'] == column_i)] print(f1_01) #indexを取得 f1_02 = f1.index[(f1['line'] == line_i) & (f1['column'] == column_i)] print(len(f1_02)) #一致しているかどうかの確認、存在していれば1つある。 if len(f1_02) == 1: #index[0]列目を変数に index_i = f1_02[0] #検索した行の結果を取得 print(f1.at[index_i,'a']) print(f1.at[index_i,'b']) print('一致しました') #結果の上書き f1.at[index_i,'a'] = 15 f1.at[index_i,'b'] = 20 print(f1) else: print('一致しませんでした') #ファイルの上書き、別の名前にしたい場合はファイル名を変える。 f1.to_csv("pandas.csv", index=False)

今までにpythonについて書いた記事はここにリンクを貼ってあります。

興味があればぜひご覧ください。

Python : 重心(図心)の検出 moments

PythonでのOpencvを使った重心(図心)求め方についてです 。

以前書いた、最小外接円でも似たような値は出せますが、

kangkang1981.hatenablog.com

最小外接円だとcontoursの関数と組み合わせる必要がありますが、

 

画面全体での白の重心という方法ではこのmomentsという関数を使います。

使い方としては、二極化あれた白画像、もしくはcontours関数の領域でも取れますが、

contoursの場合は最小外接円でも同じようにでますので、好みで構わないと思います。

 

書き方としては、二極化した画像をmomentsで囲います。

mu = cv2.moments(th_otsu)

 

こうすると、muに各モーメントの値が出るのですが、

重心は下記のようになります。

x : m10/m00

y : m01/m00

x,y= int(mu["m10"]/mu["m00"]) , int(mu["m01"]/mu["m00"])

 

元の画像はこれを使いました。

f:id:Kangkang1981:20201025204450j:plain

重心を検出すると下記のようになります。

f:id:Kangkang1981:20201025204552j:plain



参考にしたリンク先は下記となります。

labs.eecs.tottori-u.ac.jp

 

プログラムの詳細は下記になります。 

 

import cv2

#画像を読み込む
frame = cv2.imread('moon_plus.jpg')
#画像をグレイ化
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#画像を二極化
ret,th_otsu = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
#モーメント関数で3次までのモーメントを取得
mu = cv2.moments(th_otsu)
#図心を出す。
x,y= int(mu["m10"]/mu["m00"]) , int(mu["m01"]/mu["m00"])
#図心を画像に記載する。
cv2.circle(frame,(x,y),5,(0,0,255),3)
#画像を表示する。
cv2.imshow('frame',frame)
cv2.imwrite('frame_moment.jpg',frame)

#キー入力を待つ
cv2.waitKey(0)
#全ての開いたウインドウ閉じる
cv2.destroyAllWindows()

 

今までにpythonについて書いた記事はここにリンクを貼ってあります。

興味があればぜひご覧ください。

Python : Opencv BGR,青、緑、赤の分割 cv2.split(画像)

1か月ぶりの更新になってしまいました。

最近まで会社でリストラやっていた影響で、周りの人が続々といなくなるので、

公私ともにブルーなのです。

はてなブログさんより一か月も更新していませんよというのが来たので、

 書くか~と思いました。

 

今回は、Python OpencvでのBGRの分割です。

青(B)、緑(G)、赤(R)を分割する方法です。

 

まずは使うモジュールはopencvとnumpyなので、

import cv2

import numpy as np

 

画像を読み込みます。
frame = cv2.imread('lena_color.jpg')

前に使ったことのある、レナさんです。

f:id:Kangkang1981:20201006213400j:plain


画像のサイズ、チャンネル(チャンネルは不使用)を抽出します。

空の画像を作るためです。
h,w,c = frame.shape

空の画像はnumpyにて作成します。

frame.dtypeという形にすると、元の画像と同じ型になります。

zeros = np.zeros((h, w), frame.dtype) 

 

次に画像を分割します。
blue_img , green_img , red_img = cv2.split(frame)

このsplitというので分割をします。

一つ一つのイメージは1チャンネルのデータとなり、gray画像のようなデータです。

 

次にmergeという関数で、分解した色データとカラ画像を合成します。

blue_frame = cv2.merge((blue_img,zeros,zeros))

green_frame = cv2.merge((zeros,green_img,zeros))

blue_frame = cv2.merge((zeros,zeros,red_img) )

mergeは二重カッコなのですが、上のは最後のカッコは全角ですので、

コピーする際は、下のプログラムをお願いします。

よくわからないのですが、半角カッコにすると、

ちゃんと表示できなかったのですよね  

 

後は、特に必要ないのですが、縦につなげて表示すると下記のようになります。

上から順に青、緑、赤です。

f:id:Kangkang1981:20201006214114j:plain

 

詳細のプログラムは下記になります。

#opencvをインポートします。
import cv2 
import numpy as np

#画像を読み込む
frame = cv2.imread('lena_color.jpg')
#画像のサイズ、チャンネル(チャンネルは不使用)を抽出
h,w,c = frame.shape

#置き換え用のカラの画像作成
zeros = np.zeros((h, w), frame.dtype)

#BGRの分割(すべて1チャンネルの画像
blue_img , green_img , red_img = cv2.split(frame)

#青、緑、赤画像のみを抜き出し合成、
blue_frame = cv2.merge((blue_img, zeros, zeros))
green_frame = cv2.merge((zeros, green_img, zeros))
red_frame = cv2.merge((zeros, zeros, red_img))

#画像を横につなげる
frame_h = cv2.vconcat([blue_frame,green_frame,red_frame])

#画像を表示
cv2.imshow('BGR',frame_h)

#画像の保存
cv2.imwrite('lena_BGR_split.jpg',frame_h)

#キー入力を待つ
cv2.waitKey(0)
#全ての開いたウインドウ閉じる
cv2.destroyAllWindows()

 

今までにpythonについて書いた記事はここにリンクを貼ってあります。

興味があればぜひご覧ください。

Python : 画像の極座標変換 warpPolar

Opencvを使った、画像の極座標変換についてです。

またまた久々の更新です。

最近は不動産投資をするための準備で貯金がどんどん減っていく状態(TT)。。。

これ以外にも今いる会社が業績不振で黒字リストラをしているので

(会社は再構築といっていますが)

全体的に気分があまりよくなく、

後ろ向きなことばかり考えてしまっているこの頃です。

※今回は幸いなことにリストラ対象ではないのですが、何時対象になることやら・・・

 

それで本題ですが、極座標変換についてですが、

仕事で扱う製品は丸いものなのですが、今外観検査のプログラム検討をしていて、

丸を極座標にしたらどうなるかな~と思って調べてやり方がある程度分かったので、

載せておきます。

 

この月の画像を使います(検索して出てきたフリー画像です)

f:id:Kangkang1981:20200906143628j:plain



丸い画像を極座標変換する方法です。

まず変換フラグを作ります。

 キュービック補間 + 外れ値塗りつぶし + 極座標へリニアマッピング
flags = cv2.INTER_CUBIC + cv2.WARP_FILL_OUTLIERS + cv2.WARP_POLAR_LINEAR

引き数:画像, 変換後サイズ(幅、高さ)、中心座標(X座標、Y座標)、半径、変換フラグ
linear_polar = cv2.warpPolar(frame_trim, (w, h), (int(h/2), int(w/2)), int(radius+10), flags)

linear_polar = cv2.warpPolar(画像, (幅, 高さ), (中心座標x,y), 半径, flags)

左が極座標変換前、右が変換後です。

f:id:Kangkang1981:20200906142927j:plain

 

逆変換

極座標変換にフラグの部分に逆変換の部分の「cv2.WARP_INVERSE_MAP」を追加します。

flags = cv2.INTER_CUBIC + cv2.WARP_FILL_OUTLIERS + cv2.WARP_POLAR_LINEAR + cv2.WARP_INVERSE_MAP
linear_polar_inverse = cv2.warpPolar(linear_polar, (w, h),(int(h/2), int(w/2)), int(radius+10), flags)

左が変換前、右が逆変換後

f:id:Kangkang1981:20200906142939j:plain

 

極座標変換をする際の中心座標と半径は元の位置になるので、

あらかじめ知る必要があります。

このため、下記のプログラムは画像を読み込んだ後、

最小外接円を元に画像を切り出した後に極座標変換及び、逆変換をしています。

最小外接円等については下記の記事を参照ください。

kangkang1981.hatenablog.com

 

単純に極座標変換だけを書いたほうがわかりやすかったと思いますが、

変換する前に中心を取っておく必要があるので、ちょっと長めになっています。

 

プログラム詳細は下記になります。

 

#モジュールのインポート
import cv2

#画像を読み込む
frame = cv2.imread('moon.jpg')

"""
画像の中心がほしいので、contoursで検出、最小外接円で中心座標の抜き取り
"""
#gray画像を作成
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#二極化
ret2,th = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

cimg = th

contours, hierarchy = cv2.findContours(cimg,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

for i, cnt in enumerate(contours):
        # 輪郭の面積を計算する。
        area = cv2.contourArea(cnt)
        # 抽出する範囲を指定
        if area > 100 and area < 100000:
            #frme画像に書き込む
            #cv2.drawContours(frame, contours, i, (0,0,255), 5)
            #インデックスNoと面積を確認
            (x,y),radius = cv2.minEnclosingCircle(cnt)

#この画像で極座標変換をします。
frame_trim = frame[int(y-radius-10):int(y+radius+10),int(x-radius-10):int(x+radius+10)]

"""
切り取った画像のサイズ取得(cのチャンネル数はここでは不要)
"""
h,w,c = frame_trim.shape print('h : '+str(h)) print('w : '+str(w)) """ 円→極座標 """ # キュービック補間 + 外れ値塗りつぶし + 極座標へリニアマッピング flags = cv2.INTER_CUBIC + cv2.WARP_FILL_OUTLIERS + cv2.WARP_POLAR_LINEAR # 引き数:画像, 変換後サイズ(幅、高さ)、中心座標(X座標、Y座標)、半径、変換フラグ linear_polar = cv2.warpPolar(frame_trim, (w, h), (int(h/2), int(w/2)), int(radius+10), flags) """ 逆変換 極座標 → 円 """ flags = cv2.INTER_CUBIC + cv2.WARP_FILL_OUTLIERS + cv2.WARP_POLAR_LINEAR + cv2.WARP_INVERSE_MAP linear_polar_inverse = cv2.warpPolar(linear_polar, (w, h),(int(h/2), int(w/2)), int(radius+10), flags) """ 写真の合成、横に並べる """ frame_h = cv2.hconcat([frame_trim,linear_polar]) frame_h2 = cv2.hconcat([linear_polar,linear_polar_inverse]) """ 画像の表示 & 書き込み """ cv2.imshow('trim',frame_trim) cv2.imshow('linear',frame_h) cv2.imshow('linear_inverse',frame_h2) cv2.imwrite('moon_trim.jpg',frame_trim) cv2.imwrite('linear.jpg',frame_h) cv2.imwrite('linear_inverse.jpg',frame_h2) cv2.waitKey(0) cv2.destroyAllWindows()

今までにpythonについて書いた記事はここにリンクを貼ってあります。

興味があればぜひご覧ください。

Python : sinθ,cosθ,tanθ サイン、コサイン、タンジェント

Python、mathのモジュールを使ったサイン、コサイン、タンジェントの求め方です。

 

ちょっと今、図面をプログラムで書くことをやっていて、

角度を計算するときにsin,cos,tanを多用しているのもあり、載せておきます。

 

まずはmathのモジュールを使うので、インポートします。

import math

 

サイン、コサイン、タンジェントを求める場合、

エクセルもそうですが、角度を一度ラジアンに計算しなおします。

ラジアンとは、詳しくはwiki参照です。

簡単に説明するとこんな感じで一周を2πとしてその間の点に変換します。

0°     = 0

60°   = 1/3π

180° =  π

360° = 2π

 

変換方法は下記のように記述します。

変数 = math.radians(角度)

角度を60度とした場合です。。

angle = 60

radian_angle = math.radians(angle)

 

後は、サイン、コサイン、タンジェントにするのは

下記のようにmath.sin(ラジアン)のように記述します。

サイン    =  math.sin(radian_angle)
コサイン   =  math.cos(radian_angle)
タンジェント =  math.tan(radian_angle)

radian_angle = math.radians(angle

プログラムの詳細は下記です。radian_angle = math.radians(gle)

import math

angle = 60
#ラジアンを求める
radian_angle = math.radians(angle)

#サイン
sin_a = math.sin(radian_angle)
#コサイン
cos_a = math.cos(radian_angle)
#タンジェント
tan_a = math.tan(radian_angle)

#結果の表示
print(radian_angle)
print(sin_a)
print(cos_a)
print(tan_a)

 

今までにpythonについて書いた記事はここにリンクを貼ってあります。

興味があればぜひご覧ください。

Python : 動画の読み込み ループ再生

Pythonの動画読み込みをする際のループ再生をする場合です。

前回紹介した下記の記事から一部変更するだけです。

kangkang1981.hatenablog.com

 

変更する場所は、下から4行目のelse:の後に、

最初のフレームに戻す下記に変更するだけです。

cap.set(cv2.CAP_PROP_POS_FRAMES,nini_start)

このnini_startは0になっているので最初のフレームに戻りますが、

別の場所にしたければ、この数字を変更すれば途中のフレームに戻ります。

 

この内容ですが、while文の中にif文で

if ret:

とcapが存在するかを見ているのですが、このフレームがなくなるときすなわち

else:

の時に、また最初のフレームに戻すという流れになっています。

 

詳細のプログラムは下記になります。

import cv2

#動画のアドレスを指定
cap = cv2.VideoCapture('movie.mp4')
#どのフレームかた始めるか指定;0は最初から
nini_start = 0
cap.set(cv2.CAP_PROP_POS_FRAMES,nini_start)

#while文にてカメラがつながっている限りは動画撮影
while True:
    #動画を読み込む
    ret,frame1 = cap.read()
    #動画が存在するか否か
    if ret:
        #30msec待つ;これを入れないと早すぎて見れないです。
        cv2.waitKey(30)
        #画像の呼び出し
        cv2.imshow('frame1',frame1) 
        
        #qを押したら終了
        key = cv2.waitKey(1)
        if key & 0x00FF  == ord('q'):
            break
    #動画が終了したら、whileループを抜ける
    else:
#最初のフレームに戻る。 cap.set(cv2.CAP_PROP_POS_FRAMES,nini_start) #画像をすべて閉じる cv2.destroyAllWindows()

 

今までにpythonについて書いた記事はここにリンクを貼ってあります。

興味があればぜひご覧ください。

Python : 動画の読み込み

Pythonの動画の読み込み方法です。

動画の保存方法については、下記のとおりです。

kangkang1981.hatenablog.com

 

今回は、上で制作した、movie.mp4という動画ファイルを読み込む方法です。

今回もOpencvを使うので、cv2を読み込みます。

import cv2

 

動画のアドレスを指定します。

cap = cv2.VideoCapture('movie.mp4')

動画を読み込む際はどのフレームから読み込むか?というのが指定できるので、

この指定をします。0だと最初からです。

もし最初からしか見ない場合は下記の2行は不要です。

nini_start = 0
cap.set(cv2.CAP_PROP_POS_FRAMES,nini_start)

 

後は、while文にてループを組み

while True:
動画を読み込みます、frame1という名前にします。

読み込みかたは、カメラと一緒で指定した画像データ.read()です。
ret,frame1 = cap.read()

この辺のやり方は結構好みの部分もありますが、

if文で画像が存在するかどうかを見るやり方です。
if ret:
30msec待つ;これを入れないと早すぎて見れないです。

この待つ文は、if文でqを押したら終了にするため、

画像を表示する前に入れるほうが、qを押したときの反応が良いです。
cv2.waitKey(30)
画像の表示
cv2.imshow('frame1',frame1)

上で説明した「q」を押したら終了これは

基本画像を表示したすぐ後に入れておくと反応がよいです。
key = cv2.waitKey(1)
if key & 0x00FF == ord('q'):
   break

動画が終了したら、whileループを抜けるようにしておきます。

この方法でなくてもよいですが、ループを抜けられるようにしておかないと、

だんまりになってしまいます。
else:
  break

最後に画像をすべて閉じます。
cv2.destroyAllWindows()

 

詳細のプログラムは下記になります。

import cv2

#動画のアドレスを指定
cap = cv2.VideoCapture('movie.mp4')
#どのフレームかた始めるか指定;0は最初から
nini_start = 0
cap.set(cv2.CAP_PROP_POS_FRAMES,nini_start)

#while文にてカメラがつながっている限りは動画撮影
while True:
    #動画を読み込む
    ret,frame1 = cap.read()
    #動画が存在するか否か
    if ret:
        #30msec待つ;これを入れないと早すぎて見れないです。
        cv2.waitKey(30)
        #画像の呼び出し
        cv2.imshow('frame1',frame1) 
        
        #qを押したら終了
        key = cv2.waitKey(1)
        if key & 0x00FF  == ord('q'):
            break
    #動画が終了したら、whileループを抜ける
    else:
        break
    
#画像をすべて閉じる
cv2.destroyAllWindows()

 

今までにpythonについて書いた記事はここにリンクを貼ってあります。

興味があればぜひご覧ください。