アプリ版:「スタンプのみでお礼する」機能のリリースについて

C++言語で線形補間法のプログラムを組んで実行しているのですが、どしてもうまくいきません。ただ2倍の画像を作っているだけなのですが・・・。
以下プログラムを載せます、おおよその場所はわかるのですがどうすれば通るのかわかりません。どう直したらよいのか分かる方がいましたらご教授お願いします。
※bmp[0]:現画像 pic:bmp[0]の縦横2倍の画像

// 線形補間法 //
int zx = 2;
int zy = 2;
int i,j,m,n;
float x,y,p,q;
int xs = bmp[0]->Width/2;
int ys = bmp[0]->Height/2;
int d;

for(i = -ys; i < ys; i++){
for(j = -xs; j < xs; j++){
y = i/zy;
x = j/zx;
if(y > 0){
m = (int)y;
}else{
m = (int)(y-1);}
if(x > 0){
n = (int)x;
}else{
n = (int)(x-1);}
q = y - m;
p = x - n;
if(q == 1){q = 0; m = m + 1;}
if(p == 1){p = 0; n = n + 1;}
if((m >= -ys)&&(m < ys)&&(n >= -xs)&&(n < xs)){
d = (int)((1.0 - q) * (1.0 - p) * (bmp[0]->GetPixel( m + ys, n + xs)) //おそらくこの辺に問題があるかと思われます。
+ p * (bmp[0]->GetPixel( m +ys, n + xs))
+ q * (1.0 - p) * (bmp[0]->GetPixel(m + 1 + ys, n + xs))
+ p * (bmp[0]->GetPixel(m + 1 + ys, n + 1 + xs)));
}else{
d = 0;
}
if(d < 0){d = 0;}
if(d > 255){d = 255;}
pic->SetPixel(i + ys, j + xs) = d;
}
}

pictureBox2->Image = pic;
}

A 回答 (4件)

(m >= -ys)&&(m < ys - 1)の ys-1は



4ピクセルのデータを収集する際の右上と右下の +1する分を考慮しないと画素のない部分を指示してしまうためです

たとえば 120x120の大きさだった場合に
120,0 が左上だった場合 そのままだと
120,0 121,0
120,1 121,1
の4ピクセルを拾うことになりますが 実際には 121といったX座標がないためライブラリーがどこからデータを拾ってくるか分りません
エラーになってくれればまだいいのですが ・・・
    • good
    • 0

> そうすると最初にグレースケール化が必要になるのでしょうか?


> どこを見てもそんなことは書いてないのですが、どこにでもある
> このプログラムのimage_in[ ][ ]とはどういうことなのでしょう

さ~ 私には分りません
あなたのお使いの環境すら知らないのですから

当方はWindows環境で行っています
元画像がグレースケールなら グレースケール化する必要がない場合もあるでしょう
グレースケールでも8階調、256階調、65536階調などその方法は沢山あります
これをメモリー上に取り込むのも環境によってさまざまだと思います
Unix系のXの上とか、Windows上とか DOSのG-RAMを直接いじってるとか

この i,jのループの中で x,yがどのような値になるのか机上で計算してみましょう

COLORREF cl[4]d ,d;
cl[0] = bmp[0]->GetPixel( n + xs + 0, m + ys + 0 );
cl[1] = bmp[0]->GetPixel( n + xs + 1, m + ys + 0 );
cl[2] = bmp[0]->GetPixel( n + xs + 0, m + ys + 1 );
cl[3] = bmp[0]->GetPixel( n + xs + 1, m + ys + 1 );

といった具合に取得して
d.r = (int)(1.0 - q) * (1.0 - p) * cl[0].r
+ p * cl[1].r
+ q * (1.0 - p) * cl[2].r
+ p * cl[3].r;
d.g = (int)(1.0 - q) * (1.0 - p) * cl[0].g
+ p * cl[1].g
+ q * (1.0 - p) * cl[2].g
+ p * cl[3].g;
d.b = (int)(1.0 - q) * (1.0 - p) * cl[0].b
+ p * cl[1].b
+ q * (1.0 - p) * cl[2].b
+ p * cl[3].b;

pic->SetPixel( i + xs, j + ys, d );
といった具合で設定しますが

SetPixel/GetPixelなどはコストの高いメソッドなのでほとんど使いません
数点の点の描画などなら使いますが ・・・

WindowsならBITMAPオブジェクトからGetBitmapBitsなどを使ってデータを取得して
その上で配列操作を行います
    • good
    • 0
この回答へのお礼

Color color1 = bmp[0]->GetPixel(m + ys, n + xs);
r1 = color1.R; g1 = color1.G; b1 = color1.B;
Color color2 = bmp[0]->GetPixel(m + ys, n + xs);
r2 = color2.R; g2 = color2.G; b2 = color2.B;
Color color3 = bmp[0]->GetPixel(m + 1 + ys, n + xs);
r3 = color3.R; g3 = color3.G; b3 = color3.B;
Color color4 = bmp[0]->GetPixel(m + 1 + ys, n + 1 + xs);
r4 = color4.R; g4 = color4.G; b4 = color4.B;

r = (int)(((1.0 - q) * (1.0 - p) * r1) + (p * r2) + (q * (1.0 - p) * r3) + p * r4);
g = (int)(((1.0 - q) * (1.0 - p) * g1) + (p * g2) + (q * (1.0 - p) * g3) + p * g4);
b = (int)(((1.0 - q) * (1.0 - p) * b1) + (p * b2) + (q * (1.0 - p) * b3) + p * b4);
}else{
r = 0; g = 0; b = 0;

}
if(r < 0){r = 0;}
if(g < 0){g = 0;}
if(b < 0){b = 0;}
if(r > 255){r = 255;}
if(g > 255){g = 255;}
if(b > 255){b = 255;}

Color newColor = Color::FromArgb( r, g, b );
pic->SetPixel(i + ys * 2, j + xs * 2, newColor );
}
教えてもらったことと同じような感じですが、上記のようにやってみた結果うまくいきました。ありがとうございます。

それと、(m >= -ys)&&(m < ys - 1)&&(n >= -xs)&&(n < xs - 1)の部分なのですが、-1とは何のことだったのでしょう?
線形補間された画像の右と下に線があわられてしまいました。(_|のような感じ) -1を消したら何もでなくなりましたが。

SetPixel/GetPixel以外にも画素配置の方法があるということなので、調べてみます。本当にありがとうございました。

お礼日時:2008/12/17 18:00

dの数式はこのままでいいと思います


ループの i,jの範囲と SetPixelに与える座標のオフセットが問題なのではないかと思います

for ( i = -ys * 2; i < ys * 2; i++ ) {
  for ( j = -xs * 2; j < xs * 2; j++ ) {
    // xypqmnの演算
    if((m >= -ys)&&(m < ys -1)&&(n > -xs)&&(n < xs - 1)){
      // dの演算
    } esle {
      d = 0
    }
    pic->SetPixel( i + ys * 2, j * xs * 2 ) = d;
  }
}
といった具合でしょう
    • good
    • 0
この回答へのお礼

私のプログラムだと画像を2枚用意しているから2倍しているんですね。
エラーGetPixelとSetPixelの部分で、それぞれ"class に対して正しくありません。"と"関数に 2 個の引数を指定できません。"といったエラーなのですがよく考えてみたらGet(set)Pixel関数は座標指定された場所のRGBの3つデータをもらうわけですから、掛け算ができないのは当たり前です。しかし、そうすると最初にグレースケール化が必要になるのでしょうか?どこを見てもそんなことは書いてないのですが、どこにでもあるこのプログラムのimage_in[ ][ ]とはどういうことなのでしょう?

//c言語線形補間法プログラム//
#include "Params.h"

image_in; 入力画像
image_out; 出力画像
zx; (拡大率)横
zy; (拡大率)縦

void(~){
int i,j,m,n;
float x,y,p,q;
int xs = X_SIZE/2;
int ys = Y_SIZE/2;
int d;

for(i = -ys; i < ys; i++){
for(j = -xs; j < xs; j++){
y = i/zy;
x = j/zx;
if(y > 0){
m = (int)y;
}else{
m = (int)(y-1);}
if(x > 0){
n = (int)x;
}else{
n = (int)(x-1);}
q = y - m; 
p = x - n;
if(q == 1){q = 0; m = m + 1;}
if(p == 1){p = 0; n = n + 1;}
if((m >= -ys)&&(m < ys)&&(n >= -xs)&&(n < xs)){
d = (int)((1.0 - q) * (1.0 - p) * image_in[m + ys][n + xs]
+ p * image_in[m + ys][n + 1 + xs]
+ q * (1.0 - p) * image_in[m + 1 + ys][n + xs]
+ p * image_in[m + 1 + ys][n + 1 + xs]);
}else{
d = 0;
}
if(d < 0){d = 0;}
if(d > 255){d = 255;}
image_out[i + ys][j + xs] = d;
}
}
}

お礼日時:2008/12/11 19:12

何に困っているのでしょう?



このままだと 元画像の中心部分を2倍に伸張して『描画領域は同じ大きさ』で描画するのだと思いますが ・・・
    • good
    • 0
この回答へのお礼

線形補間法を使って画像のリサイズ(ここでは2倍)をするのが目的です。
最近傍法より滑らかになる画像が出力されるとのことなのでこちらを使っています。
bmp[0]には100*100pixelの画像が格納されていて、picには200*200pixelの画像が格納されています。それで拡大率であるzx(横),zy(縦)を2倍にして縦横2倍の画像(pic)を作ろうとしています。

お礼日時:2008/12/10 15:42

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!