Koordinaten einer Linie berechnen
-
Guten Morgen,
ich zeichne mittels MoveTo() und LineTo() eine Linie. Nun möchte ich jedes Pixel dieser Linie durchlaufen und die Farbe des Pixels auslesen. Meine Idee ist also jede Koordinate auszulesen, allerdings weiss ich nicht wie ich aus der Linie die einzelnen Koordinaten bekomme. Weiss vielleicht jemand wie die das am besten anstellen könnte?
Gruß
Daniel
-
Wenn du nur gerade Linien zeichnest, dürfte die Berechnung ja einfach sein -)
Bei beliebigen Linien müßtest du ja wissen, welcher Rasterungsalgorithmus intern verwendet wird, um die Linie exakt (Pixel für Pixel) auszulesen.
Der am meisten eingesetzte dafür ist der Bresenham-Algorithmus (http://de.wikipedia.org/wiki/Bresenham-Algorithmus).Ansonsten einfach die Linie selber Pixel für Pixel zeichnen (dann weißt du auch die einzelnen Pixelwerte)...
Hier noch eine Klasse, welche ich selber mal entwickelt habe:
//--------------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "CBitmap.h" #include <stdlib> #include <math.h> //--------------------------------------------------------------------------- CBitmap::CBitmap(TCanvas *cv) : m_cv(cv) { } inline void CBitmap::SetPixel(int x, int y) { m_cv->Pixels[x][y] = m_cl; } inline TColor CBitmap::GetPixel(int x, int y) { return m_cv->Pixels[x][y]; } void CBitmap::DrawLine(int x1, int y1, int x2, int y2) { if(x2-x1 >= y2-y1) { double y = y1, dy = double(y2-y1+1) / double(x2-x1+1); for(int x=x1; x<=x2; x++) { SetPixel(x, y); y += dy; } } else { double x = x1, dx = double(x2-x1+1) / double(y2-y1+1); for(int y=y1; y<=y2; y++) { SetPixel(x, y); x += dx; } } } void CBitmap::DrawRect(int x1, int y1, int x2, int y2) { DrawLine(x1, y1, x2, y1); DrawLine(x2, y1, x2, y2); DrawLine(x1, y1, x1, y2); DrawLine(x1, y2, x2, y2); } void CBitmap::DrawEllipse(int x, int y, int rx, int ry) { int px, py; double delta_angle = 1.0 / max(x, y); for(double angle=0; angle<2*M_PI; angle += delta_angle) { px = x + floor(rx * sin(angle) + 0.5); py = y - floor(ry * cos(angle) + 0.5); SetPixel(px, py); } } void CBitmap::Fill(int x, int y) { m_fill_cl = GetPixel(x, y); if(m_fill_cl != m_cl) Fill1(x, y); } void CBitmap::Fill1(int x, int y) { TRect &r = m_cv->ClipRect; int xx, yy; xx = x, yy = y; while(yy >= r.Top && GetPixel(xx, yy) == m_fill_cl) { Fill1_Line(xx, yy); yy--; } xx = x+1, yy = y+1; while(yy <= r.Bottom && GetPixel(xx, yy) == m_fill_cl) { Fill1_Line(xx, yy); yy++; } } void CBitmap::Fill1_Line(int x, int y) { TRect &r = m_cv->ClipRect; int xx, yy = y; xx = x; while(xx >= r.Left && GetPixel(xx, yy) == m_fill_cl) { SetPixel(xx, yy); xx--; } xx = x + 1; while(xx <= r.Right && GetPixel(xx, yy) == m_fill_cl) { SetPixel(xx, yy); xx++; } } /* void CBitmap::Fill1(int x, int y) { static int nDepth = 0; nDepth++; if(nDepth < 10000) { TRect &r = m_cv->ClipRect; if(x >= r.Left && x <= r.Right && y >= r.Top && y <= r.Bottom && GetPixel(x, y) == m_fill_cl) { SetPixel(x, y); Fill1(x-1, y); Fill1(x+1, y); Fill1(x, y-1); Fill1(x, y+1); } } nDepth--; } */ void CBitmap::Fill(int x, int y, TColor clOutline) { m_fill_cl = clOutline; Fill2(x, y); } void CBitmap::Fill2(int x, int y) { TRect &r = m_cv->ClipRect; int xx, yy; xx = x, yy = y; while(yy >= r.Top && GetPixel(xx, yy) != m_fill_cl) { Fill2_Line(xx, yy); yy--; } xx = x+1, yy = y+1; while(yy <= r.Bottom && GetPixel(xx, yy) != m_fill_cl) { Fill2_Line(xx, yy); yy++; } } void CBitmap::Fill2_Line(int x, int y) { TRect &r = m_cv->ClipRect; int xx, yy = y; xx = x; while(xx >= r.Left && GetPixel(xx, yy) != m_fill_cl) { SetPixel(xx, yy); xx--; } xx = x + 1; while(xx <= r.Right && GetPixel(xx, yy) != m_fill_cl) { SetPixel(xx, yy); xx++; } } /* void CBitmap::Fill2(int x, int y) { static int nDepth = 0; nDepth++; if(nDepth < 10000) { TRect &r = m_cv->ClipRect; if(x >= r.Left && x <= r.Right && y >= r.Top && y <= r.Bottom && GetPixel(x, y) != m_fill_cl) { SetPixel(x, y); Fill2(x-1, y); Fill2(x+1, y); Fill2(x, y-1); Fill2(x, y+1); } } nDepth--; } */ void CBitmap::DrawRegularPolygon(int x, int y, int r, int n, int angle) { if(n <= 2) return; // No Polygon m_cv->Pen->Color = m_cl; double d_angle = angle * M_PI / 180.0; int sx = x + floor(r * sin(d_angle) + 0.5); int sy = y - floor(r * cos(d_angle) + 0.5); m_cv->MoveTo(sx, sy); double delta_angle = 2 * M_PI / n; int px, py; for(int i=0; i<n; i++) { d_angle += delta_angle; px = x + floor(r * sin(d_angle) + 0.5); py = y - floor(r * cos(d_angle) + 0.5); m_cv->LineTo(px, py); } m_cv->LineTo(sx, sy); }
-
d@niel schrieb:
...
ich zeichne mittels MoveTo() und LineTo() eine Linie. Nun möchte ich jedes Pixel dieser Linie durchlaufen und die Farbe des Pixels auslesen.Hi,
warum machst du dir die Mühe? Bei MoveTo/LineTo wird die Linie in der Farbe
gezeichnet, die dem aktuellen Pen-Wert entspricht. Der Farbwert steht also bereits fest und ist für jedes Pixel der Linie gleich.mfg
kpeter
-
kpeter schrieb:
Der Farbwert steht also bereits fest und ist für jedes Pixel der Linie gleich.
Hallo,
und selbst wenn nicht (wenn er die Linie durch viele einzelne Punkte erzeugt), ist die Farbe im Voraus bekannt und kann "zwischengespeichert" werden - um sie im Nachhinein weiter zu verwenden. Aber vielleicht erkennen wir auch den Sinn der Aktion noch nicht
LG, Micha
-
RandomAccess85 schrieb:
Aber vielleicht erkennen wir auch den Sinn der Aktion noch nicht
Wird so sein
Vielleicht will er ja die Pixels einzeln umfärben.
Im übrigen errechnet die Funktion selbst die zu zeichnenden Pixel. Also
fragt man während der Draw-Messages die Pixelpositionen ab und wechselt ggf.
den Pen.mfg
kpeter
-
Hi,
anstatt MoveTo/LineTo kommt die WinAPI-Funktion LineDDA kommt dem Vorhaben am
nächsten.void __fastcall TForm1::Button1Click(TObject *Sender) { LineDDA( 200, 0, 5, 255, (LINEDDAPROC)LineDDACallBack, NULL ); // oder andere Werte } //--------------------------------------------------------------------------- VOID CALLBACK LineDDACallBack( int X, int Y, LPARAM lParam ) { Form1->Image1->Canvas->Pixels[X][Y] = RGB(0, 0, 0); // und hier zur Kontrolle die Pixel, in denen gezeichnet wurde: Form1->Memo1->Lines->Add("X: " + IntToStr(X) + ", Y: " + IntToStr(Y)); }
Die Callbackfunktion wird solange aufgerufen, bis die Linie gezeichnet ist.
mfg
kpeter
-
Hallo,
vielen Dank für die Antworten und sorry für meine späte Antwort.
Mal kurz etwas zu dem Hintergrund meiner Frage. Ich lade ein Bild und ziehe darauf eine Linie. Nun möchte ich halt diese Linie durchgehen und nicht die Farbe der Linie auslesen, sondern die Farbe der einzelnen Pixel die unter dieser Linie sind.
Werde mir Eure Antworten mal in ruhe anschauen und ein wenig rumprobieren.
Gruß
Daniel
-
Hallo
Dann ist LineDDA das richtige für dich. Denn in der CallBack-Funktion kannst du statt einen Farbwert zu setzen ja den bestehenden Farbwert auslesen.
bis bald
akari
-
So,
verwende nun LineDDA und es funktioniert alles bestens.Vielen Dank!
Gruß