2012-09-28 15 views
18

rysunek mam zaprojektowany program, który, w zasadzie, wycina kształt geometryczny na wiele małych trójkątów (w „lewo płótnie”), stosuje się pewne proste przekształcenie matematyczne do grona trójkątów i odświeża je w ich nowa konfiguracja. Zobacz zrzut ekranu poniżej.Qt/C++: skutecznie

screen cap 1

W celu wyciągnięcia tych trójkątów, używam QPainter::drawPolygon. Każdy trójkąt po prawej stronie odpowiada trójkątowi po lewej, więc wiem, jakiego koloru chcę użyć, by go narysować.

Jak na razie dobrze. Nawet jeśli narysuję o wiele więcej trójkątów niż to (kiedy używam dużo mniejszych trójkątów do wycinania kształtu), jest to wystarczająco szybkie.

Dodałem funkcję do mojego programu: Mogę narysować trójkąty wyodrębnione z obrazu zamiast prostych trójkątów: patrz poniższy zrzut ekranu.

enter image description here

Problemem jest to, że sposób to zrobić jest zbyt powolny. Oto jak to zrobić:

  1. biegnę przez wszystkich trójkątów
  2. Dla każdego trójkąta, ja obliczyć współrzędne każdego piksela, który zostanie wyświetlony.
  3. Dla każdego z tych pikseli, ja obliczyć współrzędne odpowiedniego piksela na zdjęciu (To jest proste działanie matematyczne) i odzyskać kolor, który piksela.
  4. używam QPainter::setPen(QColor) i QPainter::drawPoint(QPoint) rysować piksel.

Jestem nowy w programowaniu w Qt i nie wiem nic o grafice, więc to mogę wymyślić. Problem polega na tym, że jest on "niedopuszczalnie" zbyt wolny (paintEvent każdego płótna zajmuje około 0,15 s, w porównaniu z 0,01 w przypadku trójkątów prostych).

Pobiegłem profilera aby spróbować zrozumieć, co się dzieje, zauważyłem, że w poświęca widget płótno na paintEvent,

  1. 58% czasu spędza w QPainter::drawPoint
  2. 27% czasu w QPainter::setPen

wydaje się, że QPainter::drawPoint jest zbyt skomplikowany i powolny: chcę po prostu go wydrukować piksel danego koloru, to jest to.

może znalazłem rozwiązania mojego problemu: przechowywać QImage (jako zmienna członkiem mojego widget płótnie), która reprezentuje całość Chcę moje płótno do wyświetlania i zdefiniować go całkowicie w moim paintEvent piksel po pikselu, a następnie narysuj go od razu na końcu mojego . Mam wskazówkę, że będzie to znacznie szybsze. Ale zanim ponownie napiszę mój kod, chciałbym się dowiedzieć, czy to naprawdę jest to, co chcę zrobić.

Mam nadzieję, że nie urodziła można zrobić śmierć! Z góry dziękuję za wasze spostrzeżenia.

+1

rysujesz piksel po pikselu ?? (zomg !!) – UmNyobe

Odpowiedz

4

dla OPENGL rozwiązanie:

pomocą buforu RGB dla docelowego obrazu. Wykonaj 3 pierwsze kroki, tak jak wcześniej. Po znalezieniu pozycji i koloru piksela, ustaw go na tym buforze. Następnie można użyć obrazu do skonstruowania obrazu na podstawie poprzedniego bufora. Jest blisko rozwiązania, które podałeś i będzie znacznie szybsze niż obecnie.

+0

Wielkie dzięki!Prawdopodobnie wykorzystam to (dopóki nie nauczę się o OpenGL pewnego dnia). – Seub

+2

Potwierdzam, to jest w porządku za to, co robię! (paintEvent w maks. 0,04 s) – Seub

7

OpenGL robi zdjęcie (tekstury) współrzędnych mapowania naprawdę dobrze. Prawdopodobnie chcesz użyć jakiejś formy OpenGL. Qt ma pewne powiązania z OpenGL, które mogą ci pomóc.

+0

+1 Zgoda, OP wydaje się tworzyć aplikację mapowania UV, OpenGL jest idealnym narzędziem do tego. – cmannett85

+0

Dziękuję za odpowiedź! Na pewno zajrzę to pewnego dnia. Problem polega na tym, że nie wiem nic o OpenGL. – Seub

3

Jednym ze sposobów na to byłoby użycie klasy dziedziczącej z QGLWidget zamiast z zestawu QGraphicsScene/QGraphicsView. Niestety, krzywa uczenia się dla OpenGL zaczyna się trochę stromo. Będzie to jednak bardzo szybkie, ponieważ nastąpi bezpośrednio na karcie graficznej, która jest zoptymalizowana pod kątem tego rodzaju operacji.
Załadujesz obrazek QGLWidget::bindTexture().
Powiążesz punkty obrazu za pomocą siatki trójkątów i prześlesz je na kartę graficzną. W starszej wersji OpenGL (który jest łatwiejszy w użyciu niż nowszym API moim zdaniem), to będzie wyglądać mniej więcej tak:

glEnable(GL_TEXTURE_2D); 

glBegin(GL_TRIANGLES); 
for (int ii=0;ii<triangle.size();++ii) { 
    for (int jj=0;jj<3;++jj) { 
    glTexCoord2d(triangle[ii].tex[jj][0],triangle[ii].tex[jj][1]); 
    glVertex2d(triangle[ii].point[jj[0],triangle[ii].point[jj][1]); 
    } 
} 
glEnd(); 

Gdzie triangle jest pewne struktury danych, które zostały wykonane trzymając wierzchołki trójkąta i skojarzone odwzorowania do obrazu. Karta graficzna poradzi sobie z interpolacją pikseli.

+0

Dziękuję bardzo za odpowiedź! To jest bardzo ciekawe. "Niestety, krzywa uczenia się dla OpenGL zaczyna być trochę stroma". Myślę, że to jest problem dla mnie! Ale prawdopodobnie będę musiał się o tym dowiedzieć w pewnym momencie. – Seub

+0

Używa to wycofanego kodu. Naprawdę chcesz używać shaderów i samplerów tekstur. – doron

+0

@doron Jest przestarzałe. Ale jeśli funkcja stacjonarnego potoku wykona zadanie, o wiele łatwiej będzie przejść tą drogą. GLSL tylko zwiększa trudność w nauce programowania 3D. Daje to większą elastyczność, ale także kodowanie. Jest jednak powód, dla którego większość z nas nie programuje zbyt wiele w montażu. – JCooper

1

Inną opcją poza OpenGL jest użycie OpenCL, co może być łatwiejsze. Trzeba tylko mapować bitmapę wejścia/wyjścia na kartę graficzną, napisać trochę jądra w C, które obsługuje jeden trójkąt, a następnie kolejkować wykonanie jądra dla każdego trójkąta. To zadziała nawet 100 razy szybciej niż pojedynczy rdzeń procesora.

Jest wrapper Qt dla gospodarza API OpenCL tutaj:

http://doc.qt.digia.com/opencl-snapshot/index.html

0

Innym rozwiązaniem jest wykorzystanie do przycinania i transformacje już realizowane skutecznie w silniku farby raster. Dopóki transformacja między dwoma trójkątami może być wyrażona za pomocą macierzy transformacji rozszerzonej 3x3, wystarczy ustawić ją na docelowym malarzu, a następnie narysować cały obraz źródłowy na celu. Zostanie przycięty i przekształcony, aby wypełnić trójkąt docelowy. Możesz także po prostu narysować prostokąt ograniczający trójkąta źródłowego, zamiast całego obrazu, jeśli profilowanie ma dla niego zaletę.

Można to zrównoleglić, aby równolegle przetwarzać tyle trójkątów, ile jest rdzeni procesora.

Powiązane problemy