いつも大変お世話になっております。
ピクセルの値を「ゼロ(黒)」にしたピクセルを読み込んでも「255(白)」となってしまい困っています。cvShowImageでこの画像を表示すると、どうみてもその場所は黒です。
なぜ「255(白)」になるのかわからず困っています。
原因を教えていただけませんでしょうか。
詳細は以下のとおりです。
out_imgという変数名のCV_LOAD_IMAGE_COLORの真っ白の画像
out_img = cvLoadImage("C:...\shiro.jpg", CV_LOAD_IMAGE_COLOR);
の6×6ピクセルの値を、以下の文で「黒」にして
out_img->imageData[out_img->widthStep * 6 + 6 * 3] = 0;
out_img->imageData[out_img->widthStep * 6 + 6 * 3 + 1] = 0;
out_img->imageData[out_img->widthStep * 6 + 6 * 3 + 2] = 0;
保存し、再び(別のソリューションで)src_img変数としてこの画像を読み込み
src_img = cvLoadImage("C:...¥shiro.jpg", CV_LOAD_IMAGE_COLOR);
グレースケール化し、
src_img_gray = cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1);
tmp_img = cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1
ゼロイチの2値化(バイナリ画像)に変換し、
cvCvtColor(src_img, src_img_gray, CV_BGR2GRAY);
閾値でゼロイチに変換した後(なぜか上のsrc_img_grayでは黒がゼロにはならないため)
cvAdaptiveThreshold(src_img_gray, tmp_img, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, 8);
6×6の位置の値(変数iro)を確認すると「255」となります。
for (x = 0; x < tmp_img->width; x = x + 1){ // x 座標を 1ピクセルずつ進める
for (y = 0; y < tmp_img->height; y = y + 1){ // y 座標を 1ピクセルずつ進める
if (x == 6 && y == 6){
x = 6; (ここでデバックを掛けて、下の変数iroの値がいくつかを確認しています。ゼロであってほしいのですが、255です。
}
uchar iro = tmp_img->imageData[tmp_img->widthStep * y + x * 3];
if (iro == 0){
画像読み込みの引数がおかしいのだろうと思い、
CV_LOAD_IMAGE_ANYCOLOR や「0」にしたところ
今度はfor文のところでエラーになり、走査が始まりません。
for (x = 0; x < tmp_img->width; x = x + 1){ // x 座標を 1ピクセルずつ進める
for (y = 0; y < tmp_img->height; y = y + 1){ // y 座標を 1ピクセルずつ進める
初歩的な質問で申し訳ありません。
ぜひアドバイスをいただけると助かります。
どうぞよろしくお願い致します。
A 回答 (2件)
- 最新から表示
- 回答順に表示
No.2
- 回答日時:
imgData の中は、次のようにデータが並んでいます
0 * widthStep から
X=0,Y=0のデータ
X=1,Y=0のデータ
...
X=x,Y=0のデータ
...
X=width-1,Y=0のデータ
1 * widthStep から
X=0,Y=1のデータ
X=1,Y=1のデータ
...
X=x,Y=1のデータ
...
X=width-1,Y=1のデータ
y * widthStep から
...
X=x,Y=yのデータ
...
y * widthStep から
...
X=x,Y=yのデータ
...
(height-1)*widthStepから
...
X=width-1,Y=height-1のデータ
各座標データは次のようになっています
チャンネル1のデータ
チャンネル2のデータ(2チャンネル以上のとき)
チャンネル3のデータ(3チャンネル以上のとき)
チャンネル4のデータ(4チャンネル以上のとき)
各チャンネルのデータは IPL_DEPTH_* で示されるバイト数だけ使われます。
IPL_DEPTH_8U なら1バイト
IPL_DEPTH_32F なら4バイト
以上のことから、座標(x,y)のチャンネルch のデータは
imageData[ y * widhtStep + 1データあたりのバイト数 * ( x * 総チャンネル数 + (ch -1)) ]
から始まる 「1データあたりのバイト数」のデータ、ということになります
で
out_img = cvLoadImage("C:...\shiro.jpg", CV_LOAD_IMAGE_COLOR);
だと、おそらく IPL_DEPTH_8U(1バイト), チャンネル数3になっているはずです。
これだと
out_img->imageData[out_img->widthStep * y + x * 3] = 0; // 3チャンネルのうちのチャンネル1: B
out_img->imageData[out_img->widthStep * y + x * 3 + 1] = 0; // 3チャンネルのうちのチャンネル2: G
out_img->imageData[out_img->widthStep * y + x * 3 + 2] = 0; // 3チャンネルのうちのチャンネル3: R
となります。
/* 元の画像が 6x6 なら、 x=6,y=6という座標は存在しません。 */
/* よって out_img->widthStep * 6 + 6 * 3 は間違いです */
ですが
cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1)
だと、IPL_DEPTH_8U(1バイト), チャンネル数1 です。
imageData[ y * widhtStep + 1データあたりのバイト数 * ( x * 総チャンネル数 + (ch -1)) ]
にあてはめれば
imageData[ y * widhtStep + 1 * ( x * 1 + (1 -1)) ]
です。
前にも言ったと思いますが、C言語では、配列の範囲外かどうかのチェックはしません。
例え範囲外でも、とにかくそのアドレスをアクセスしに行きます。
ちゃんと正しい範囲かどうかを管理するのは、プログラム制作者の仕事です。
そこが不完全なら、まずは、チェックしてくれるSet/Getを使って「正しい処理」をするプログラムを作ることから始めてはどうでしょうか。
No.1
- 回答日時:
> out_img->imageData[out_img->widthStep * 6 + 6 * 3] = 0;
> out_img->imageData[out_img->widthStep * 6 + 6 * 3 + 1] = 0;
> out_img->imageData[out_img->widthStep * 6 + 6 * 3 + 2] = 0;
これでは座標(6,6)であり、6x6の画像(x=0~5,y=0~5)に存在しない点です
> なぜか上のsrc_img_grayでは黒がゼロにはならない
JPEGで保存しているようですが、JPEGは非可逆圧縮を使っています。
不可逆とは、元に戻らない、という意味です。
「見た目が似ていれば、ちょっとくらい色が違っていてもいい」という考えで、高圧縮率を実現しています。
元の色が黒(0)だったら、JPEG保存したものを読み出したときに「だいたい黒(1とか2とか)」になってればいい、というものです。
そのまま扱いたいのなら、PNG等の可逆圧縮やBMP等の非圧縮形式を使いましょう。
> uchar iro = tmp_img->imageData[tmp_img->widthStep * y + x * 3];
なぜ x *3 になっているのですか?
前にも言いましたが、配列や画像の範囲について注意が足りません。
まずは、imageDataに直接アクセスするのではなく、 cvSet2D/cvGet2D やcvSetReal2D/cvGetReal2D で x,y を指定するようにしては。
imageDataを使いたいのなら、C言語の配列とポインタをしっかり学習してマスターしてからにしましょう。
kmee様
すぐに回答くださってありがとうございます。
いろいろと今回もミスを教えてくださって助かりました。
pngにしてみたところゼロになりました。
画像の拡張子にも注意します。
できればぜひ、もうひとつ教えていただきたいのですが
なぜimageDataの場合、「*3」は不要なのでしょうか?
いくら2値にしたとはいえ、配列はRGBなので
3番目の値=画素値、だと理解していました。
cvSet2Dなどを使用してみますが、
なぜimageDataでRGB画像の場合に「*3」ではNGなのか
自分で調べた結果の理解ですので、
恥ずかしいのですが混乱しています。
もし教えていただけると嬉しいです。
よろしくお願い致します。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- HTML・CSS 【HTML】【CSS】【Swiper】 元の画像は横1200×縦600なのですが、実際のサイト上に反 5 2022/07/16 13:57
- Perl RSSにdiv,ul classを付けたいのですがどのようにつけるのかわからないです 2 2022/03/28 01:53
- JavaScript jQueryで同じクラス名のものを別物として扱いたい 1 2022/06/17 14:14
- Perl 画像が表示でnull; this.src 1 2022/04/19 11:31
- JavaScript html5に変えるとスライドショーが消えてしまった。 3 2022/03/26 19:53
- HTML・CSS CSSが効かずどのように指定すれば良いか分からないのでアドバイスお願い致します 2 2023/06/07 12:25
- JavaScript アップロードファイルの種類によって処理を分岐させたいのですが書き方が分からずアドバイスお願いします 4 2023/06/17 19:12
- PHP PHP echo バックスラッシュの使い方 img要素 2 2023/01/08 22:46
- JavaScript 画像の表示位置 3 2022/12/23 08:25
- PHP 共通の処理をまとめる方法がわからないのでアドバイスお願いします。 1 2022/12/19 20:20
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
javascriptでのパスについて
-
画像を入れ替えたい
-
複数画像のランダム複数表示(...
-
ダイアログから画像ファイルは...
-
jqueryのスライドショー。html...
-
テキストにマウスオーバーで画...
-
MAX関数を使ってからLEFT JOIN...
-
htmlの記述で link rel=styles...
-
画像の上に画像リンクを貼る方法
-
スライダーを実装した場合、ペ...
-
背景色を一定時間ごとにランダ...
-
文字を固定したいのですが…
-
javascriptでURLにマウスオーバー
-
[急ぎ] videoタグで埋め込んだm...
-
文字と数字が混在する要素のsor...
-
離れた場所にマウスオーバーで...
-
ホームページビルダー15 メニュ...
-
c++std::string型をTCHARに変換...
-
タブで開いてさらにタブ内をア...
-
1行で左寄せと右寄せと中央揃え...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
JavaScriptで変更した属性の元...
-
MFCで画像を表示させているので...
-
画像が表示でnull; this.src
-
error LNK2019 未解決のシンボ...
-
Vb.net2005での画像の合成方法
-
onclickで画面が固まる・・・ら...
-
リンク先を動的に変更する
-
(javascript)HTMLで指定した...
-
【OpenCV】二値画像後、白の部...
-
jQuery 複数のfind()
-
ラズパイでno module named zbar
-
外部javascriptの重複を防ぐには
-
条件分岐でキーが入力されてい...
-
かぶらないランダム画像
-
HTMLからimgのsrcのみを正規表...
-
pythonで、tkinterとpillowの組...
-
OpenCV での画素値の比較について
-
imgボタンにfocusの当て方
-
指定したフォルダの画像を一括...
-
OpenCVでサンプルコードを使う...
おすすめ情報