• ベストアンサー

(C言語)スキャンライン法による三角形作成

こんにちは! 先週C言語のプログラミングの課題が出て土日もずっと考えたのですが全く意味が分かりません>< どなたか教えてください泣 内容は、スキャンライン法で二次元三角形を作り(三角形の塗りつぶし)、BMPファイルへ出力せよというものです。 1. 3角形を囲む長方形・ (xmin,xmax,ymin,ymax) 2. Y座標をymax~yminまで, 1ずつ減らしながら以下を繰り返す (a)スキャンラインSL(Y=y)発生 (b)SLと3角形との交点(線形補間) (c)交点間の画素を 表示色(r,g,b)で塗る *端点や水平線に注意 よろしくお願いします><

noname#152791
noname#152791

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

>スキャンラインY=yが何を意味するのか分からないし スキャンラインSLのY座標をyとする、ということです。 スキャンラインSLは、水平な直線です。 そのY座標をyとした時に、SLと三角形の辺との交点を求めます。 交点が2つ有る場合、交点の座標は(x1,y)と(x2,y)になるので 2つの交点の間を塗りつぶす(=2つの交点の間に線を引く) この処理を、Y座標をyminからymaxまで変えながら行う。

その他の回答 (2)

  • hashioogi
  • ベストアンサー率25% (102/404)
回答No.2

海苔巻きを作るときに使用する「すだれ」を竹の棒が横になるようにぶら下げて水彩絵の具ですだれに絵を描いてみてください。竹の棒の一本一本がスキャンラインです。 筆を左右上下に動かして、すだれ全体に絵を描くのではなく、竹の棒を一本一本塗る感じで絵を書く感じです。 線形補間というのは比例を使用した補間です。早い話が、すだれの左下を原点として竹の棒の向きをx軸として考えてすだれの上に三角形を書くと、三角形の各辺はy=ax+bの形に表すことができます。頂点を除いて、それぞれの竹の棒は三角形の2つの辺と交差すると思いますから、2つの辺の交点を求めて、竹の棒のその間を塗っていけばいいでしょう?

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

わからない箇所はどこでしょう? 方眼紙を用意してください。 そこに三角形を書いてください。 その三角形が収まるマスが「1」 ある横方向に並んだマス目に注目して、三角形の辺があるマスに色を塗るのが 「2」 二つの頂点を通る直線と、Y=yの交点を求めるのは、算数か数学でやったはず。 むずかしいのはBMPファイルの出力で、C言語の標準では、そのものずばりのものはありません。

noname#152791
質問者

補足

見ていただいてありがとうございます! 最初に以下のソースファイルとヘッダファイル1つとwriteBmp.cというファイルが渡されたのでBMPファイルが出力できるのだと思います。 課題はこのソースファイルに付け足すというものです! スキャンラインY=yが何を意味するのか分からないし、線形補間が何かを調べたんですが理解ができなくて困っています>< /* 24ビットBMPファイルの書き込み */ #include "cg.h" #include "writeBmp.c" /* ビットマップデータの生成 */ void mbitmap(int width, int height) { int i, j; for (i=0; i<height; i++) for (j=0; j<width; j++) { Pixel[i][j][0] = (unsigned char)255; Pixel[i][j][1] = (unsigned char)255; Pixel[i][j][2] = (unsigned char)0; } } void main(void) { int width = 640, height = 480; /* ビットマップデータの生成 */ mbitmap(width, height); /* 24ビット-ビットマップファイルへの書き込み */ bmpout("sample.bmp", width, height); }

関連するQ&A

  • Scilabを使ったジュリア集合の描画プログラム

    今、Scilabを使用してジュリア集合(充填およびそれ以外を含む集合)を描画するプログラムを書いています。 以前書いたC言語のプログラムをもとに書いているのですが、正確に描画できません。どうしたらよいでしょうか。教えてください。 与える条件は右上と左下の座標(複素数形式)と定数Cの値です。 以下に掲載したのが製作したプログラムです。 よろしくお願い致します。 //描画エリアの右上と左下の座標を複素数で設定する Z =[ -1.2-1.2*%i;1.2+1.2*%i]; //複素定数(C)を設定する C=0+0*%i; //描画エリアのx座標とy座標の各最小値と最大値を計算する。 xmin = min(real(Z)); xmax = max(real(Z)); ymin = min(imag(Z)); ymax = max(imag(Z)); Cr = real(C); Ci = imag(C); //描画点数を800×800に設定する。 N = 800; //各増分を計算する。 dx = (xmax-xmin)/(N-1); dy = (ymax-ymin)/(1-N); //プロットデータを"0"で初期化 map=zeros(N,N); //ジュリア集合の描画 i=1; for X=xmin:dx:xmax j=1; for Y=ymax:dy:ymin for k=1:30 x = X ^ 2 - Y ^ 2 + Cr; y = 2 * X * Y +Ci; if x^2 +y^2 > 4 then break; end map(j,i)=k; X=x; Y=y; end j=j+1; end i=i+1; end //プロットするための設定 Re = xmin:dx:xmax; Im = ymax:dy:ymin; clf(0); Sgrayplot(Re,Im,map');

  • C++ グラフ作成

    sin と cosのグラフを作成しようとしているのですが、思うように行かず、悩んでいます。 一応試行錯誤の結果、下のようなプログラムを書いたのですが、コンパイルが成功しても何も表れないという悲しい現実が待っていました。*を表示させる部分を省くと、グラフが書けるのですが、そもそも三角関数を扱っているのにxを角度で表現するということすらできません。 有識者の方の回答をお待ちしています。よろしくお願いします。 なお、開発環境はwindows visual studio 2008のC++です。 #include <stdio.h> #include <math.h> #define Xmax 40 #define Ymax 40 char a[Xmax][Ymax],x,y; int myf(float x); int main(void){ for(x=0;x<Xmax;x++){ for(y=0;y<Ymax;y++){ a[x][y]=' '; } } for(y=0;y<Ymax;y++){ a[Xmax/2][y]='-'; } for(x=0;x<Xmax;x++){ a[x][Ymax/2]='|';} a[Xmax/2][Ymax/2]='+'; for(x=0;x<Xmax;x++){ for(y=0;y<Ymax;y++){ int y = myf(sin(x)); if(y>=0&&y<=1) a[x][y]='*'; } } for(x=0;x<Xmax;x++){ for(y=0;y<Ymax;y++){ int y = myf(cos(x)); if(y>=0&&y<=1) a[x][y]='*'; } } for(x=0;x<Xmax;x++){ for(y=0;y<Ymax;y++){ printf("%c",a[x][y]); } printf("\n"); } } int myf(float x){ double sin(double x); double cos(double x); y=sin(x); y=cos(x); return 5*cos(x); }

  • 現在、エクセルで、選択したグラフの大きさや縦横軸を統一するマクロを作成

    現在、エクセルで、選択したグラフの大きさや縦横軸を統一するマクロを作成中です。 以下のようなマクロまでは作ることができましたが、ひとつだけ不満があります。 それは、初期値です。 できれば、最初に選択したグラフの設定を初期としてダイアログの入力欄に記入してある状態にしたいのですが、どうすればよいかわかりません。 知恵を貸してください!! よろしくお願いいたします!!! Sub 選択したグラフ縦横軸変更() Dim chartObj As ChartObject Dim myObj As Object Dim xmin As Double Dim xmax As Double Dim ymin As Double Dim ymax As Double xmin = Application.InputBox("x軸最小値") xmax = Application.InputBox("x軸最大値") ymin = Application.InputBox("y軸最小値") ymax = Application.InputBox("y軸最大値") For Each myObj In Selection Set chartObj = ActiveSheet.ChartObjects(myObj.Name) With chartObj.Chart.Axes(xlCategory) .MaximumScale = xmax .MinimumScale = xmin End With With chartObj.Chart.Axes(xlValue) .MaximumScale = ymax .MinimumScale = ymin End With Next myObj End Sub

  • MATLABで画像軸のスケール変更をしたいのですが、 スケールだけのへ

    MATLABで画像軸のスケール変更をしたいのですが、 スケールだけのへんこうはできますか? axis ([xmin xmax ymin ymax])だと画像サイズを超えた際に余白が白くなってしまいます。 画像サイズはそのままで縮尺サイズだけ変更したいです。 どなたかお願いします

  • エクセルの1シート内にある複数の散布図のx軸とy軸の最大目盛、最少目盛

    エクセルの1シート内にある複数の散布図のx軸とy軸の最大目盛、最少目盛、目盛間隔を揃えるにはどのようにしたら良いか教えてください。いくつかwebsiteで調べて下記のようにしてみましたが、x軸の目盛を変更するところで、失敗してしまいます。 よろしくお願いします。 Sub XY軸() Dim Ymin Ymin = InputBox("Y軸の最少?") If IsNumeric(Ymin) Then Range("C2").Value = Ymin Else MsgBox "入力NG!" End If Dim Ymax Ymax = InputBox("Y軸の最大?") If IsNumeric(Ymax) Then Range("C3").Value = Ymax Else MsgBox "入力NG!" End If Dim Y Y = InputBox("目盛間隔?") If IsNumeric(Y) Then Range("C4").Value = Y Else MsgBox "入力NG!" End If Dim xmin xmin = InputBox("X軸の最少?") If IsNumeric(xmin) Then Range("D2").Value = xmin Else MsgBox "入力NG!" End If Dim Xmax Xmax = InputBox("X軸の最大?") If IsNumeric(Xmax) Then Range("D3").Value = Xmax Else MsgBox "入力NG!" End If Dim X X = InputBox("Xの目盛間隔?") If IsNumeric(X) Then Range("D4").Value = X Else MsgBox "入力NG!" End If Dim co As ChartObject For Each co In ActiveSheet.ChartObjects With co.Chart With .Axes(xlValue) .MinimumScale = Range("C2").Value '最小値 .MaximumScale = Range("C3").Value '最大値 .MajorUnit = Range("C4") '目盛間隔 End With With .Axes(xlCategory) .MinimumScale = Range("D2").Value '最小値 .MaximumScale = Range("D3").Value '最大値 .MajorUnit = Range("D4") '目盛間隔 End With End With Next End Sub

  • ビットマップを二値化した後の座標取得のご相談

    ビットマップを二値化した後の座標取得のご相談 最近VB6.0からVC++2008(Express Edition)に乗り換えて画像処理を試みています(WinXP).現在,長方形が写っているビットマップ画像を二値化して,指定範囲内の長方形の平均高さ(白を抽出)を調べようとしています.WEBや文献など調べて,二値化するところまではできたのですが,二値化後の白黒画像の座標値の読み方が分からないため,長方形の高さを算出することができません.もしよろしければご助言いただけましたら幸いに思います. ─────────────────────────────────── VB6.0プログラム(二値化後の処理の部分) Dim Xmin As Double, Xmax As Double //X方向 Dim Ymin As Double, Ymax As Double //Y方向 Dim SumY As Double, AveY As Double Dim Pix As Double ' Xmin = 0 Xmax = Shape1.Width SumY = 0  //長方形の高さの合計 AveY = 0  //長方形の高さの平均 ' For X = Shape1.Left To Shape1.Left + Shape1.Width Ymin = 0 Ymax = 0 ' For Y = Shape1.Top To Shape1.Top + Shape1.Height //囲んだ四角部分において '   //※この下の部分をVC++2008でどのようにすれはいいかわかりません・・・ If picturebox1.Point(X, Y) = RGB(255, 255, 255) Then //白があれば If Ymin = 0 Then //Yminが0であれば Ymin = Y //YminはY End If If Ymax < Y Then //YmaxがYより小さかったら Ymax = Y //YmaxはY End If End If ' Next Y SumY = SumY + Ymax - Ymin //Xごとの長方形の高さの合計 Next X ' AveY = SumY / Xmax //平均高さの算出 ─────────────────────────────────── ここからVC++2008(二値化と計算を一気に行えればいいなと思ってます) for (j = 0; j < rect.Height; j++) {  for (i = 0; i < rect.Width; i++){ //輝度値の取得 B = pBuf[i * Step + j * bmpData->Stride]; //青 G = pBuf[i * Step + 1 + j * bmpData->Stride]; //緑 R = pBuf[i * Step + 2 + j * bmpData->Stride]; //赤 //輝度値の設定(二値化) if ((B >= Threshold) || (G >= Threshold) || (R >= Threshold)) { //白に変換  pBuf[i * Step + j * bmpData->Stride] = 255; //青  pBuf[i * Step + 1 + j * bmpData->Stride] = 255; //緑  pBuf[i * Step + 2 + j * bmpData->Stride] = 255; //赤  //※ここに何かいれればいいと思うのですが,上記の  //※If(picturebox1.Point(X,Y)=RGB(255,255,255))に代わる書き方が分かりません… } else { //黒に変換 pBuf[i * Step + j * bmpData->Stride] = 0; //青 pBuf[i * Step + 1 + j * bmpData->Stride] = 0; //緑 pBuf[i * Step + 2 + j * bmpData->Stride] = 0; //赤 } } 参照WEB http://imagingsolution.blog107.fc2.com/blog-entry-40.htm

  • アプレットは初期化されていません

    いつもお世話になっています。 早速ですが、appletviewerで見たときにタイトルのように「アプレットは初期化されていません」と出てきます。これを解決するにはどうすればいいのでしょうか?  ちなみに私が作っているのは白黒のみの画像をロードして、黒い部分を四角で覆い重心を求めるというものです。ソースを載せておきます。 import java.applet.*; import java.awt.*; import java.awt.image.*; public class test extends Applet { Image img; // 元のイメージ int img_width = 0; // 元のイメージの幅 int img_height = 0; // 元のイメージの高さ int pix[]; // 元のイメージを格納する配列 int wcnt_pix[]; // 行ごとの黒画素数を格納する配列 int hcnt_pix[]; // 列ごとの黒画素数を格納する配列 int cnt = 0; // 黒画素のカウント用 int cnt_sum = 0; // 黒画素のカウント総数 int chu = 0; // 中心値 int sum1 = 0; int sum2 = 0; int x = 0; int y = 0; int xmax = 0; // 黒画素の右端 int xmin = 0; // 黒画素の左端 int ymax = 0; // 黒画素の上端 int ymin = 0; // 黒画素の下端 public void init(){ img = getImage(getDocumentBase(), "test.jpg"); // イメージのロード MediaTracker mt = new MediaTracker(this); mt.addImage(img, 0); try{ mt.waitForID(0); }catch(InterruptedException e){} // イメージのロード完了まで待機 img_width = img.getWidth(this); // 元のイメージの幅を取得 img_height = img.getHeight(this); // 元のイメージの高さを取得 cntpix(); box_top(); box_bot(); box_rig(); box_lef(); } // 黒画素数のカウント public void cntpix(){ pix = new int[img_width * img_height]; wcnt_pix = new int[img_width]; hcnt_pix = new int[img_height]; try{ PixelGrabber pg = new PixelGrabber(img, 0, 0, img_width, img_height, pix, 0, img_width); pg.grabPixels(); }catch(InterruptedException e){} // 行ごとのカウント for(int wj = 0; wj < img_height; wj++){ cnt = 0; for(int wi = 0; wi < img_width; wi++){ if((pix[wj * img_width + wi] & 255) < 128){ cnt++; } } wcnt_pix[wj] = cnt; cnt_sum = cnt_sum + cnt; } // 列ごとのカウント for(int hi = 0; hi < img_width; hi++){ cnt = 0; for(int hj = 0; hj < img_height; hj++){ if((pix[hj * img_width + hi] & 255) < 128){ cnt++; } } hcnt_pix[hi] = cnt; } chu = cnt_sum / 2; // 中心値 // 中心値より重心が何行目かを求める int i = 0; while(sum1 < chu){ sum1 = sum1 + wcnt_pix[i]; i++; } x = i - 1; // 中心値より重心が何列目かを求める int j = 0; while(sum2 < chu){ sum2 = sum2 + hcnt_pix[j]; j++; } y = j - 1; } // 黒画素の上端を求める public void box_top(){ int ti = 0; while(wcnt_pix[ti] == 0){ ymax = ti; ti++; } } // 黒画素の下端を求める public void box_bot(){ int bi = img_height; while(wcnt_pix[bi] == 0){ ymin = bi; bi--; } } // 黒画素の右端を求める public void box_rig(){ int ri = 0; while(hcnt_pix[ri] == 0){ xmin = ri; ri++; } } // 黒画素の左端を求める public void box_lef(){ int li = img_width; while(hcnt_pix[li] == 0){ xmax = li; li--; } } // 画像等の描画 public void paint(Graphics g){ int dx = x - xmin; // 重心のX座標 int dy = y - ymax; // 重心のY座標 g.drawImage(img, 0, 0, this); g.drawString("このイメージの幅は"+img_width+"で高さは"+img_height+"です。", 0, 20); // 画像の描画 g.drawLine(xmin, ymax, ymax, ymax); g.drawLine(xmin, ymax, xmin, ymin); g.drawLine(xmin, ymin, xmax, ymin); g.drawLine(xmax, ymax, xmax, ymax); // バウンディングボックスの描画 g.setColor(Color.red); g.drawString("重心は、( "+dx+", "+dy+" )です。", 0, 60); // 重心の描画 g.drawLine(x-10, y, x+10, y); // 重心の位置の描画 g.drawLine(x, y+10, x, y-10); // 重心の位置の描画 } }

    • ベストアンサー
    • Java
  • 線形補間法プログラム(C++)

    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; }

  • よろしくお願いします。

    よろしくお願いします。 使用ソフトは FLASH MX2004でアクションスクリプトは2.0です。 ムービー内のボタンをクリックすると 指定範囲をビットマップ形式で印刷できるようにしたいと思っています。 myButton.onRelease = function() { var my_pj = new PrintJob(); var myResult = my_pj.start(); if(myResult){ myResult = my_pj.addPage (0, {xMin : 0, xMax: 400, yMin: 0, yMax: 400}); myResult = my_pj.addPage ("myMovieClip", {xMin : 0, xMax: 400, yMin: 400, yMax: 800},{printAsBitmap:true}, 1); myResult = my_pj.addPage (1, null,{printAsBitmap:false}, 2); myResult = my_pj.addPage (0); my_pj.send(); } delete my_pj; } 検索して出てきたサイトに載っていたスクリプトをそのまま使い、 これで、指定範囲を印刷することはできたのですが、 ベクターデータで印刷されてしまい、 lineTo でムービー上に描きだした透明度のある線画をうまく印刷できません。 上のスクリプトは http://help.adobe.com/ja_JP/Flash/10.0_UsingFlash/WSB7FB8B27-9DF4-4089-9434-8AFF31584DA4.html#WS550687E1-ACF0-4b73-841A-7AF8F41D6340 に掲載されているもの、そのままなのですが、 これをどう修正すると ビットマップで透明度を認識する印刷ができるようになるのでしょうか? アクションスクリプト2.0でも、できるようなのですが、 説明を読んでも理解できず、ご教授いただけると助かります。 また、同様にwebで再生されたムービーからボタン操作で指定範囲をjpegでパソコン内に保存できるようにしたいのですが、 少し調べた範囲では、アクションスクリプト2.0では難しいようなのですが、 これをできる方法はありますでしょうか? 以上、ご回答よろしくお願いします。

    • ベストアンサー
    • Flash
  • エクセルでの値の補間法について教えて下さい。

    エクセルでの値の補間法について教えて下さい。 下記URLに置かれたファイルについてですが、 http://www.mediafire.com/?witwwn2djem 列Aに値X、列BにXに対応する値Yが与えられています。 ここで、X、Yの値から 値X'に対応するY'の値を線形補間によって求めるにはどうしたらよいか 教えて頂けませんでしょうか?よろしくお願いします。

専門家に質問してみよう