Przekształacanie obrazu w czasie rzeczywistym

0

Mam komputer z dwoma monitorami (lub laptop z dodatkowym monitorem). Monitory pracują w trybie rozszerzonego pulpitu. Chciałbym zrobić coś takiego, że na jednym monitorze jest wyświetlony całkowicie dowolny obraz (np. aplikacja, film, gra komputerowa), moja aplikacja pobiera na bieżąco ten obraz (cały ekran lub wskazany fragment, np. obszar odtwarzania filmu na stronie YouTube), przetwarza ten obraz w jakiś sposób (dorysowuje coś, zmienia kolory, rozciąga) i wyświetla go na drugim ekranie.

Wiem, że cały problem to jest zrzut ekranu, praca na bitmapie, a potem wyświetlanie obrazu i umiałbym to zrobić, ale jak to najlepiej zrobić żeby spełnić następujące warunki:

  1. Zrzut i wyświetlanie obrazu jest synchronizowane z wyświetlaniem obrazu na monitorach (następuje co każde odświeżenie lub co drugie lub ewentualnie co trzecie odświeżenie obrazu).
  2. Możliwy jest zrzut dowolnej treści (zauważyłem, że czasem nie wychodzi zrzut obrazu z odtwarzacza video).
  3. Bez żadnego wstępnego przygotowania wyświetlanego materiału.

Zakładam, że algorytm samego przetwarzania trwa mniej czasu niż jedno odświeżenie obrazu na monitorze (przy odświeżaniu 60Hz). Czy timery i wyświetlanie obrazu na formie (za pomocą kontrolki typu PictureBox) to dobry pomysł, czy są lepsze sposoby? W jaki sposób wykonywać automatyczny zrzut ekranu? Jak zapewnić synchronizację zrzutu i wyświetlania bitmapy z częstotliwością odświeżania monitora?

Znane mi są technologie:

  1. C# z Windows Forms i GTK#
  2. C++ z Qt
  3. Java z Swing
    W jakiej technologii to najlepiej zrealizować? Mi to jest obojętne, w której, ale chciałbym wybrać taką, która się najlepiej nadaje do tego celu.
    Ma działać w systemie Windows.

Przykłady działania:

  1. Na jednym monitorze jest wyświetlany film lub gra komputerowa w oknie, a na drugim monitorze jest wyświetlona kopia obrazu tej gry na pełnym ekranie (powiększony obraz wnętrza okna).
  2. Na jednym monitorze są wyświetlane zdjęcia lub film stereoskopowy (obrazy obok siebie), a program na drugim ekranie wyświetla ten sam obraz w formie anaglifu.
  3. Na drugim monitorze jest wyświetlany ten sam obraz, co na pierwszym monitorze, ale z inną jasnością, kontrastem i w negatywie (bez użycia regulatorów monitora).
0

Witam. Chętnie się dołączam do pytania. Dodatkowo zastanawia mnie czy jeśli by użyć WPF (którego nie znam hehe) zamiast Windows Forms nie można by było więcej osiągnąć ciekawych efektów? Dodam że sam jestem świeży w programowaniu, natomiast jakoś rok temu zostałem dobrze nakierowany tutaj w sprawie właśnie odczytu i przetwarzania obrazu z użyciem Bitmap.LockBits przez Azarien - thanks, co później doprowadziło do użycia wskaźników itd. To było C++/CLI. Teraz przesiadam się powoli na C#. Ogólnie ciekawy temat fajnie by było jakby ktoś nas pokierował.

0

Przetestowałem podstawę działania tego programu w C#/WinForms i w C++/Qt. Podstawa to jest wykonanie zrzutu obrazu określonego obszaru i wyświetlenie tego obrazu na formularzu.

W przypadku C#/WinForms zrzut wykonywałem za pomocą procedury CopyFromScreen, a wyświetlanie za pomocą DrawImage, gdzie obiekt Graphics był zbudowany na podstawie uchwytu okna (Graphics.FromHwnd(this.Handle)).

W przypadku C++/Qt zrzut wykonałem za pomocą metody grabWindow dostępnej w klasie QScreen, a wyświetlanie za pomocą metody setPixmap na etykiecie QLabel.

W obu przypadkach utworzyłem osobny wątek oraz timer "tykający" co sekundę W tym osobnym wątku tworzyłem nieskończoną pętlę, w którym było samo wykonanie zrzutu i jego wyświetlanie. W tej pętli jest też licznik iteracji. Timer wywołuje procedurę, która pobiera i wyświetla wartość licznika i zeruje go. W ten sposób wyświetlam liczbę iteracji na sekundę, czyli de facto liczbę obrazów na sekundę.

W obu przypadkach zauważyłem, co następuje:

  1. Jeżeli w pętli jest zrzucenie i wyświetlenie obrazu (również wtedy, gdy wyświetlany jest inny obraz niż zrzucany), pętla wykonuje się ok. 30 razy na sekundę bez względu na rozdzielczość obrazu.
  2. Jeżeli w pętli jest samo zrzucanie obrazu, to wykonuje się ona ok. 60 razy na sekundę bez względu na rozdzielczość obrazu.
  3. Jeżeli w pętli jest samo wyświetlanie obrazu, to wykonuje się ona kilkaset razy na sekundę (zależy od rozdzielczości obrazu), tylko wtedy menedżer zadań wykazuje duże obciążenie procesora.

Rozumiem, że 60 obrazów wynika z częstotliwości odświeżania monitora. Dlaczego jednak przy zrzucaniu i wyświetlaniu częstotliwość odświeżania jest ograniczona do 30, pomimo, że nie obciąża komputera, innymi słowy, dorzucenie paku prostych operacji na obrazie w pętli nie zmniejsza ilości obrazów na sekundę?

W C#/WinForms zrobiłem taką próbę, że w pętli było samo zrzucanie obrazu (punkt nr 2), a wyświetlanie zrobiłem w osobnym wątku uruchamianym co iterację, bezpośrednio przed kolejnego zrzutu. Po tym zabiegu, uzyskałem 30 obrazów na sekundę zamiast 60, pomimo, że czynność wyświetlania jest w osobnym wątku i teoretycznie wyświetlanie i zrzucanie następuje jednocześnie. W C++/Qt nie powtórzyłem tej próby, bo to tylko komplikuje program. Z czego wynika to, że nie da się zmusić programu do jednoczesnego wyświetlania i zrzucania obrazu?

Czy ograniczenia wynikają z właściwości Winforms i Qt, czy z czegoś innego i w żadnej technologii się tego nie przeskoczy?

0

Do tematu wróciłem przez przypadek po dłuższym czasie.

W międzyczasie opracowałem projekt, który stał cię dość dużym kombajnem i na jego potrzeby było zapytanie w tym wątku: https://github.com/andrzejlisek/LivePic

Projekt jest w C++/Qt, w Windows 8 jest opisane ograniczenie do 60FPS w przypadku braku zmian obrazu, bądź 30FPS przy występowaniu zmian w obrazie. Natomiast w Fedora 20.04 nie ma ograniczenia i ograniczeniem jest wydajność procesora, w praktyce uzyskuję ponad 300FPS, co nie ma żadnego uzasadnienia w tym przypadku, dlatego dorobiłem throttling (usypianie wątku na zadany czas w każdym cyklu).

1 użytkowników online, w tym zalogowanych: 0, gości: 1