質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Q&A

解決済

4回答

2485閲覧

メモリに収まりきらない複数枚の画像の中央値計算方法

Kenichir

総合スコア28

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

0グッド

1クリップ

投稿2020/01/27 06:54

メモリに収まりきらない複数枚の画像の中央値を計算するのに困っています。

同じサイズの画像2~100枚を重ね合わせて、画素ごとの中央値を算出することでコンポジット処理のような画像処理をしたいです。
例えば、風景に通行人が写ってしまった画像を複数枚用意し、通行人は移動しているため画素ごとに中央値などの処理をすることで風景のみを取り出す、というようなことをしたいです。

中央値ではなく、平均値ならば随時処理が可能であり、メモリに画像全てを載せる必要がないのですが、平均値ですと外れ値に強く影響されてしまうので(上の例だと、派手な色の服をきた人が通った部分は、その色に強く影響される)、外れ値にあまり影響されずなおかつメモリに全ての画像を保持しなくてもいいような合成方法を探しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

各画像を左上、中央上、右上、左中段、中央、…のように分割して一度ファイルに出力して、左上だけで中央値計算をする、のようにしてはいかがでしょうか? (9分割の必然性はないです。)

投稿2020/01/27 07:05

majiponi

総合スコア1720

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kenichir

2020/01/27 08:18

分割して計算する考えはありませんでした...参考にさせていただきます! 実はこの処理の前に、1枚目の画像を基準に2枚目からの画像を位置合わせをする処理を行っています。 この場合、位置合わせ後の画像を一時的にどこかに保存させて、分割して読み込み合成し、終わったら位置合わせ画像を削除、のようなアルゴリズムになるでしょうか?
majiponi

2020/01/28 02:56

そんな感じですね。
guest

0

真の中央値をどうにかして求める方法に関する回答にはなりませんが…

話の用途的には,
画像群{1枚目,2枚目,3枚目 ..., 99枚目, 100枚目}のすべてを使わずとも,適当に間引いてもよいのではないかと思います.

例えば,{20,40,60,80,100}の5枚だけでやるとか.
もちろん,どの程度間引くかはデータ次第(例えばこの例だと「20枚な時間周期で人が往復している」シーンを相手にすれば,人の画素値を算出してしまう箇所が生じる)ですが,
単純に間引くのではなくて20枚ごとの平均画像を用いるだとか,工夫の余地はあるかと思います.


[追記]
背景の画素値が撮影期間内において概ね一様であると仮定できるならば,
100枚分の画素値を正直に100データとして保持せずともランレングス的なデータで保持することで略一様な期間のデータを小さく持つことができるのではないかな…とか.
このとき,「レングス」が短すぎるデータは保持せずに捨ててよいハズ.
すると,100枚程度の期間なら,最終的には画素あたり多くても数個程度のデータになるのではないかな,とか思う.
結果としてデータが1個ならばそのデータの画素値を背景とできるし,複数個なら(その中で画素値が近いやつは1つにまとめて)一番時間が長いデータをやはり背景とできる…と思う.

計算量を気にしなくてよいなら,前記のランレングス的データは,
「時間方向の輝度値の変動をある誤差内で直線で近似可能な期間」のデータみたいな?
(直線の「傾き」がでかいデータは捨ててよい,とか)

投稿2020/01/27 07:27

編集2020/01/27 09:16
fana

総合スコア11658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kenichir

2020/01/27 08:01

ご回答ありがとうございます。 その通りで、厳密な中央値でなくとも、間引けばデータ数が削減できてコードも完結になるのですが、おっしゃっている通り「データ次第」で工夫が必要なためできればデータに依らず何らかの外れ値に影響されない統計量を出したいなあと行ったところです! 最終的には、データを間引くなどしたいと思います。ありがとうございます!
guest

0

ベストアンサー

画素ごとに 0 ~ 255 の256個のビンによるヒストグラムを作成し、各フレームごとに逐次カウントしていき、最後にヒストグラムから中央値を求めればよいのではないでしょうか。

この場合、画素ごとにヒストグラムを持っておけばいいので、計算に必要な配列の大きさは (画像の高さ, 幅, 256) で済みます。

ヒストグラムが与えられたデータから,中央値を求める方法|数学|苦手解決Q&A|進研ゼミ高校講座|ベネッセコーポレーション

追記

最初に書いたヒストグラムの案もそのサイズだと厳しいので、「ブロックごとに中央値を直接計算する」または「ブロックごとにヒストグラムを計算して、中央値をあとから計算する (枚数が256枚以上ならこちらのが省メモリ)」になるかと思います。

コード

OpenCV のサンプル動画 vtest.avi をフレームごとに切り出して保存した画像で試しました。

python

1from pathlib import Path 2 3import cv2 4import matplotlib.pyplot as plt 5import numpy as np 6 7# 画像のパス一覧を取得する。 8input_dir = Path("input") # 画像があるディレクトリ 9img_paths = list(input_dir.glob("*.png")) 10 11# 1枚だけ読み込み画像の幅、高さを取得する。 12img = cv2.imread(str(img_paths[0])) 13h, w = img.shape[:2] 14 15 16median_img = np.empty_like(img) 17 18stride_y, stride_x = 300, 300 # ブロックの大きさ 19for y in range(0, h, stride_y): 20 for x in range(0, w, stride_x): 21 # ブロックごとに中央値を計算する。 22 values = [] 23 for path in img_paths: 24 img = cv2.imread(str(path)) 25 values.append(img[y : y + stride_y, x : x + stride_x]) 26 median = np.median(values, axis=0).astype(np.uint8) 27 median_img[y : y + stride_y, x : x + stride_x] = median 28 29# 結果を可視化する。 30fig, ax = plt.subplots() 31ax.imshow(median_img[..., ::-1]) 32 33plt.show()

イメージ説明

投稿2020/01/27 07:05

編集2020/01/27 08:37
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yuki23

2020/01/27 07:11

それだと画像100枚分より大きくなっちゃいますね
tiitoi

2020/01/27 07:41 編集

動画のように数千、数万フレームある場合でもこの方法はメモリ使用量は固定です。 確かに、100枚程度であれば、全部読み込んで中央値を計算したほうがメモリ使用量は少ないです。そのぐらいであれば、今日のメモリ事情であれば、全部読み込んで計算しても問題ないように思いますが、メモリに乗り切らないのでしょうか? より使用メモリを少なくしたい場合は1画素ずつ for で回して中央値を計算すればよいと思います。 ---- 追記: yuki23 さんを質問者さんのコメントと勘違いしてました。失礼しました。
fana

2020/01/27 07:31

質問文では「メモリに収まりきらない」「画像2~100枚」と言っているので,メモリが厳しい環境で動作させるのではないか?と想像します.
tiitoi

2020/01/27 07:36

すいません。質問文を見落としてました。 100枚でも全部読み込むのは厳しいということですね。 使用可能なメモリと画像サイズはいくつなのでしょうか? 画像は3チャンネルのRGB画像でチャンネルごとに中央値を計算するということですかね。
Kenichir

2020/01/27 08:10

ご回答とありがとうございます。普通のPCで動作させるのですが、一眼レフでとった画像を処理したく、 一枚6000*4000*3のサイズでuint8だとすると一枚あたりおよそ70MBの使用量となってしまいます。 PCのメモリは8GBなので、114枚でメモリが枯渇する計算になります。さらにPC全体で8GBのメモリなので、OS動作や他のタスクで用いるメモリを考えると100枚でも厳しいかなあ...と できればメモリ使用量2GB以内で行きたいところです。
tiitoi

2020/01/27 08:17

なるほど。確かにそのサイズだと100枚でも厳しいですね。 ヒストグラムを作成する方法でも8Gオーバーしてしまいますね。 少し考えてみます。 ちなみに画像のリサイズ等はなしの方針でしょうか?
Kenichir

2020/01/27 08:24

人物を除去するという目的の他に、夜景など暗いところで撮った時のガサガサなノイズ(ISOノイズ)を除去するという役割も兼ねたいと思っています。実際に平均値や比較明合成などを計算したところ、ノイズ除去にはかなり有効なので... つまり高画質化するという目的も兼ねているので出力画像は入力画像と同じサイズにしたいです。 処理途中でダウンサンプリングして何らかの処理をした後に最終的に入力画像と同じサイズにする、などは考えておりますが...
tiitoi

2020/01/27 08:42

縮小したら、あとからサイズを戻したとしても画質は劣化するので、それを避けたいのであれば、他の回答者さんが書いているようにブロックごとに計算していくのが、メモリ量が一定で済むのでいいかと思います。 ブロックごとに計算していく場合、6000*4000 だとそれなりに時間がかかると思うので、ブロックサイズはメモリに乗り切るギリギリまで大きくしたほうがよいです。 OpenCV や PIL だと画像の一部を HDD から読み込むということができないので、高速化したい場合は画像の一部だけ読み込む機能があるライブラリを探すか、自作すれば高速化する余地もあると思います。
Kenichir

2020/01/27 08:46

サンプルコードまでつけてくださってありがとうございます! 他の方のコメントでも分割して処理する、というアイデアがあり、自分には浮かばなかったのでとても参考になりました。ありがとうございます。 ただ、実はこの処理の前に、1枚目の画像を基準に2枚目からの画像を位置合わせをする処理を行っています。 この場合、位置合わせ後の画像を一時的にどこかに保存させて、分割して読み込み合成し、終わったら位置合わせ画像を削除、のようなアルゴリズムになるでしょうか?
tiitoi

2020/01/27 09:03 編集

位置合わせをする理由は、撮影した画像によってカメラの位置が多少ずれているということでしょうか? 中央値の計算と位置合わせを同時にやろうとするとややこしくなるので、おっしゃるとおり、先に位置合わせ後の画像を一時的にHDDに保存してから、中央値を計算でよいと思います。
fana

2020/01/27 09:06

(しかし位置合わせをするには前景の影響を除去しないと…みたいなジレンマがあったりして.)
tiitoi

2020/01/27 09:14

> fana さん 確かに前景がどの程度変化するのかわからないですが、位置合わせと中央値の計算がどっちも先にやらないといけない関係だと困りますね。 位置合わせのほうは、画像ごとに前景が多少変化するにしても、一致率が高い位置で無理やり合わせてしまうとか。
fana

2020/01/27 09:19

まぁ,そういうのも含めて想定データ次第ですよね. オプティカルフローの多数決的にやったりすると,カメラの目の前を人が横切ったりしたらそっちが優勢になりますし… (背景に特徴が疎とかの場合も困るかな?)
Kenichir

2020/01/27 09:19

このプログラムの全容を伝えておらずすみません! 三脚が禁止されている場所でも、綺麗な画質で手ブレなく撮ったり、映り込んでしまった人物を消すために、手持ちで連写した写真や動画、iphoneのlive photosのようなものを入力として与えます! 位置合わせの方は、SURF特徴量のようなもので十分可能ですし、もし信頼できる精度未満の場合は処理から弾くなど、安定して処理できています。 やはり、位置合わせ後にデータを一時保存が一番シンプルそうですね。 ありがとうございます。
guest

0

画像から動いているものを消したいなら、中央値ではなく、最頻値だと思います。
使用する画像の数を減らすのは、とても良いと思います。

投稿2020/02/04 00:10

mbnife

総合スコア15

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kenichir

2020/02/04 10:21

回答ありがとうございます。 最頻値ですと、画像の輝度値が0〜255に対して、少ない画像枚数ではヒストグラムに山ができない、または2つ以上の山ができる可能性を考慮して最頻値は適さないと判断しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問