Strona 1 z 3

Problem z funkcją pobierania ramek z własnej dll

: 05 paź 2009 03:01
autor: smiga
Korzystając z pierwszej wypowiedzi witam serdecznie .

Od razu przepraszam za ewentualne "lamerstwo" - mimo dojrzałego wieku, w LabVIEW stawiam pierwsze kroki.

Nasza firma zajmuje się analizą obrazu w 3D, a od niedawna też w 2D (zazwyczaj jest odwrotnie - my zrobiliśmy "nawigację 3D" dla medycyny, a że nie chce się sprzedawać to "suwmiarkę 3D" dla przemysłu ... też słabo, więc wskoczyliśmy w 2D :) ) Aplikacja ma za zadanie rozpoznawać obiekty (śrubki) i wykorzystuje nasze własne algorytmy analizy obrazu (okazały się sprawniejsze od dostępnych na rynku).
Chciałem więc sprawdzić jak można przerzucić działający system do LabVIEW ... może udostępnić dla szerszego grona urzytkowników.
I tu pora skończyć chwalenie się i przejść do konkretów opisujących problem.

Mam problem z jedną z funkcji do pobierania ramek z kamery, która to funkcja dostępna jest w napisanej przez kolegę dll'ce (pisane w C++ BDS)
Funkcja "GrabFrame" zwraca wskaźnik do tablicy 2 wymiarowej HxW (w naszym przypadku kamera 1024x768). Niestety albo nie mogę ustawić parametrów w "Call Library Function Note", albo nie wiem jak wykorzystać referencję do odczytania takiej tablicy z pamięci.

Nagłowek bibliotekiwygląda następująco:

Kod: Zaznacz cały

#ifndef CameraH
#define CameraH

typedef unsigned char UINT8;

extern "C" __declspec(dllexport) void* __stdcall TCamera_Create();
extern "C" __declspec(dllexport) void __stdcall TCamera_Destroy(void* p);
extern "C" __declspec(dllexport) int __stdcall TCamera_CamInit(void* p, int CamNum, int* Height, int* Width, int* SerialNum);
extern "C" __declspec(dllexport) int __stdcall TCamera_CamStop(void* p);
extern "C" __declspec(dllexport) int __stdcall TCamera_GrabFrame(void* p, UINT8** buff8);
extern "C" __declspec(dllexport) void __stdcall TCamera_SetExposure(void* p, int exposure);

#endif
A tak wygląda Vi - funkcja GrabFrame pomiędzy czerwonymi liniami.
Obrazek
Obrazek
Obrazek

W tej wersji programu Indicator "buff8 2" zwraca jakiś wskaźnik do jakiegoś miejsca w pamięci, ale nie wiem co z tym dalej mogę zrobić - jak pobrać stamtąd tablicę z danymi?

W wersji drugiej
Obrazek
Obrazek
Obrazek

W tej wersji programu tablica "buff8 2" jest niestety pusta (same zera) - jak pobrać tablice z danymi?

Dodam, że kolega w C++ wywołuje funkcję GrabFrame ze wskaźnikiem do wskaźnika do tablicy. Drugi kolega w Delphi zrobił test - zadeklarował tablicę 1 elementową, wywołał funkcję GrabFrame ze wskaźnikiem do tej tablicy i w odpowiedzi otrzymał w tej tablicy wskaźnik do tablicy HxW (on wiedział co z tym dalej zrobić) - czyli u niego gra. Jak to zrobić w LabVIEW?

Z góry dziękuję za wszelkie podpowiedzi.

Problem z funkcją pobierania ramek z własnej dll

: 05 paź 2009 09:31
autor: vugie
W Twoim przypadku poprawna jest wersja 2, z jadną małą poprawką - ponieważ tablica zdefiniowana jest jako podwójny wskaźnik, zamiast "Array Data Pointer" musisz użyć "Array Handle" (czy jakoś tak - piszę z pamięci). "Handle" w terminologii LabVIEW oznacza właśnie wksaźnik do wskaźnika.
Po ikonkach poznaję, że użyłeś automatycznego importu DLL-ki. Z doświadczenia - nie radzę. Pomimo, że uzywam dużo odwołań do zewnętrzych DLL jeszcze NIGDY nie zdarzyło mi się by taki import był w 100% poprawny, a poprawek jest zawsze tyle, że zwykle szybciej robić to ręcznie, albo napisać coś co zrobi to półautomatycznie dla danego przypadku.

Re: Problem z funkcją pobierania ramek z własnej dll

: 05 paź 2009 16:17
autor: smiga
Niestety nie w każdym przypadku wynik jest ten sam (jak na obrazku dla wersji 2) - czyli Array Data Pointer, Array Handle i Array Handle Pointer działają w tym przypadku identycznie ... albo dają identyczny rezultat.

Może jakieś dodatkowe podpowiedzi...?

Problem z funkcją pobierania ramek z własnej dll

: 05 paź 2009 17:14
autor: vugie
jakbyś zapisał w 8.2 to mógłbym się dokładniej przyjrzeć. I razem z VI dla pszczególnych funkcji dll (przynajmniej tych ze screena)

Re: Problem z funkcją pobierania ramek z własnej dll

: 05 paź 2009 18:39
autor: wino
Może pomoże zmiana typu danych z Array Hendle, na opcję Adapt To Data Type(chyba jest taka opcja). Wtedy wyjście/wyjście funkcji zaadaptuje się do podpiętego typu danych. Jeśli podepniesz dwuwymiarową tablicę na wejściu bloczka to wybrana funkcja na wyjściu zwróci wypełnioną tablicę.

Re: Problem z funkcją pobierania ramek z własnej dll

: 05 paź 2009 22:06
autor: smiga
Załączyłem pliki w wersji 8.2
Biblioteki camera, camera1 i camera2 (bo takie katalogi można tam znaleźć) są praktycznie identyczne. Jedyna różnica to dodana jedna funkcja TCamera_GrabFrame_forArek(void* p, unsigned char* buff8, int H, int W), która miała być prostszą wersją poprzedniej, a z którą mam ten sam problem - w tych VI'ach jej nie użyłem.

Re: Problem z funkcją pobierania ramek z własnej dll

: 05 paź 2009 22:15
autor: smiga
wino pisze:Może pomoże zmiana typu danych z Array Hendle, na opcję Adapt To Data Type(chyba jest taka opcja). Wtedy wyjście/wyjście funkcji zaadaptuje się do podpiętego typu danych. Jeśli podepniesz dwuwymiarową tablicę na wejściu bloczka to wybrana funkcja na wyjściu zwróci wypełnioną tablicę.
Zmieniłem w 2 wersji na Adapt To Type (we wszystkich 3 możliwych opcjach) i w każdej efekt końcowy jest identyczny jak dotychczas - tablica 1024x768 z samymi zerami. :-\

Problem z funkcją pobierania ramek z własnej dll

: 06 paź 2009 09:57
autor: vugie
Adapt to type nie powinno zadziałać w tym przypadku.

Rozumiem, że wszystkie kombinacje typu podawania tablicy i wywołania (C i stdcall) nie działają. Sugeruję sprawdzić jeszcze zmianę wątku wywołania (z "Run in UI thread" na Reentrant). W przypadku podwójnego wskaźnika musi być "Array Handle" i kropka. Ja zwykle używam pojedyńczego wskaźnika - tak jak w funkcji "for Arek". Ale jest jedno ważne zastrzeżenie - funkcja musi pod ten adres wrzucać dane bez żadnej alokacji pamięci (musi zakładać, że wystarczająca ilość pamięci jest pod podanym adresem zaalokowana). Programiści C++ zwykle mają opory w tej sytuacji... Używam wyłącznie wywołania typu C (stdcall tylko w przypadku dll-ek winapi) i jako Reentrant (kto by chciał pakować coś jeszcze do wątku interfejsu).

Zakładam, że DLL-ka skompilowana jest jako 32-bitowa.
Weź funkcję z deklaracją UINT8** i najpierw skonfiguruj parametr buff jako I32 "Value" i zobacz co wychodzi. Powinno być 0 (a dokładniej na wyjściu powinno być to samo co na wejściu. Jeżeli nie jest to DLL-ka jest źle zrobiona. Następnie zmień Value na "Pointer to Value" i zobacz co wychodzi. Powinna wychodzić liczba zmienna z wywołania na wywołanie. Jeżeli jest to dobra nasza. Dalej opiszę jak znajdę odpowiedni materiał, bo z pamięci to mogę namieszać.

Re: Problem z funkcją pobierania ramek z własnej dll

: 06 paź 2009 14:30
autor: smiga
Po pierwsze bardzo dziękuję kolegom za zaangażowanie w mój problem (szczególnie vugie - chapeau bas!).
...wszystkie kombinacje typu podawania tablicy i wywołania (C i stdcall) nie działają
- dokładnie tak.
Sugeruję sprawdzić jeszcze zmianę wątku wywołania (z "Run in UI thread" na Reentrant)
- ten sam efekt.
Weź funkcję z deklaracją UINT8** i najpierw skonfiguruj parametr buff jako I32 "Value" i zobacz co wychodzi. Powinno być 0 (a dokładniej na wyjściu powinno być to samo co na wejściu. Jeżeli nie jest to DLL-ka jest źle zrobiona. Następnie zmień Value na "Pointer to Value" i zobacz co wychodzi. Powinna wychodzić liczba zmienna z wywołania na wywołanie.
Gdy ustawiłem buff jako I32 Value na wyjściu jest to samo co na wejściu. Niestety gdy zmienię na Pointer to Value efekt jest ten sam - na wyjściu to samo co na wejściu. :-\

Odnośnie funkcji "GrabFrame for Arek" to nie do końca rozumiem problemu z alokacją pamięci. Przecież ja w LabVIEW tworzę tablicę (podpięta do wejścia funkcji), którą funkcja ma tylko wypełnić danymi...?... no właśnie, dlaczego to też nie działa? - wiesza LabView...

Re: Problem z funkcją pobierania ramek z własnej dll

: 06 paź 2009 17:12
autor: vugie
smiga pisze:Odnośnie funkcji "GrabFrame for Arek" to nie do końca rozumiem problemu z alokacją pamięci. Przecież ja w LabVIEW tworzę tablicę (podpięta do wejścia funkcji), którą funkcja ma tylko wypełnić danymi...?... no właśnie, dlaczego to też nie działa? - wiesza LabView...
Właśnie takie zachowanie sugeruje, że funkcja robi coś więcej niż tylko wpisanie danych bezpośrednio pod podany adres - np. próbuje ją zwolnić... albo pisać poza jej obszarem - właśnie zauważyłem - w VI dla funkcji "for Arek" musisz podać na buff zainicjalizowaną tablicę - o żądanej wielkości i wypełnioną wszystko jedno czym.

Re: Problem z funkcją pobierania ramek z własnej dll

: 17 paź 2009 19:45
autor: smiga
Witam ponownie,

Chwilka przerwy od problemu niestety go nie rozwiązała :-w ...więc wracam do tematu.

Testowałem dziś jeszcze raz obie funkcje.
GrabFrameforArek wywołuję tablicą 1024x768 wypełnioną zerami. Program czasami się wiesza, a czasami przechodzi bez problemu zwracając jakieś śmieci w tablicy wyjściowej (ponowne uruchomienie to te same śmieci,. a ponowne uruchomienie LabVIEW to inne śmieci) - czyli chyba czyta jakiś "nie ten" obszar pamięci.
GrabFrame wywołane w ten sam sposób jak wyżej zwraca tablicę z samymi zerami (lub wartościami, którymi wywołuję - to też sprawdziłem). Nie ma znaczenia czy ustawię na Array Data Pointer czy Array Handle, a nawet Array Handle Pointer.

Co tu jeszcze można zrobić ... zmienić ...?

Problem z funkcją pobierania ramek z własnej dll

: 18 paź 2009 21:36
autor: vugie
Na tym etapie, to bez kodu funkcji to można tylko pozgadywać. A najlepiej to poproś kolegów, żeby wygenerowali DLL z tymi samymi funkcjami, tylko niezależne od sprzętu - żeby tam był na stałe wrzucony jakiś obrazek (np. goła baba), to pokombinujemy dalej. Nie można przecie odpuścić takiej zniewagi...

Re: Problem z funkcją pobierania ramek z własnej dll

: 19 paź 2009 22:48
autor: smiga
W tej bibliotece camera.dll funkcja GrabFrameforArek jest niezależna od sprzętu - wypełnia się kolejnymi liczbami od 0 do 255.

U mnie nie działa - czyli zwraca to samo co dostaje na wejściu ... a przy okazji wiesza LabVIEW.

A może kolega, bardzo po koleżeńsku :) , napisze i skompiluje w C (lub czymś innym) bibliotekę z funkcją robiącą to samo, czyli wypełniającą tablicę jakimiś kolejnymi liczbami - zobaczymy czy wtedy u mnie zadziała i co ewentualnie robię źle ... z góry dziękuję :)

Re: Problem z funkcją pobierania ramek z własnej dll

: 20 paź 2009 10:04
autor: vugie
Nie mogę się podłączyć u siebie do tej dll-ki. Wyskakuje, że nie ma vcl100.bpl. Przydałby się też przynajmniej plik nagłówkowy, żeby być na fest pewnym, że dobrze się podłączam.
smiga pisze: A może kolega, bardzo po koleżeńsku :) , napisze i skompiluje w C (lub czymś innym) bibliotekę z funkcją robiącą to samo, czyli wypełniającą tablicę jakimiś kolejnymi liczbami - zobaczymy czy wtedy u mnie zadziała i co ewentualnie robię źle ... z góry dziękuję :)
A zanim coś takiego zmajstruję, to zapytam się nieśmiało, czy ta kamera nie jest przypadkiem kolorowa? Bo jeśli tak to kolega podpina tablicę 3 razy za małą...

Re: Problem z funkcją pobierania ramek z własnej dll

: 20 paź 2009 14:02
autor: vugie
Płoszę bałdzo.
Projekt w Dev-C++, skompilowany przy użyciu MinGW, ale dla MSVC nie powinno być specjalnej różnicy.
Chodzi od pierwszego kopa.