Autor Wątek: Optymalizacja kopiowania tablic pikseli.  (Przeczytany 2693 razy)

Offline Charibo

  • Redaktor

# Listopad 06, 2013, 21:36:27
Cześć,

Mam pewną trudność - otóż potrzebuję przekopiować teksturę z IplImage (struktura używana przez OpenCV, a w moim przypadku OpenCVSharp) do Texture2D z Unity3D. Szybkie i brudne kopiowanie nie zdało egzaminu. W moim kodzie próbowałem używać czegoś plus-minus takiego:
void IplImageToTexture2D (IplImage displayImg)
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            float b = (float)displayImg[i, j].Val0;
            float g = (float)displayImg[i, j].Val1;
            float r = (float)displayImg[i, j].Val2;
            Color color = new Color(r / 255.0f, g / 255.0f, b / 255.0f);
            videoTexture.SetPixel(j, height - i - 1, color);
        }
    }
    videoTexture.Apply();
}
Jednak jako-tako wydajność mam tylko dla tekstury 320x176. Tymczasem marzyłaby mi się rozdzielczość HD. Po pobieżnym dość profilowaniu, ustaliłem że za tragiczną wydajność odpowiada sama pętla kopiująca wartości, nie zaś Texture2D.Apply (Apply wykonuje się w kilkanaście/dziesiąt ms, tymczasem  pętla zajmuje po 200, 250ms co klatkę).

Stąd też moje pytanie do braci warsztatowej - czy są jakieś sposoby, żeby ogarnąć to szybciej? Mam w zanadrzu mały workaround używając wbudowanej w Unity3D WebCamTexture, ale nie chciałbym go stosować, bo tracę wtedy kontrolę nad ustawieniami kamery. Dodatkowo, nie wiem jak używać unsafe w Unity i nie wiem czy to w ogóle możliwe. Czy mogę liczyć na jakieś pomysły? :) Nie muszę chyba dodawać, że moje google jest tępe i nic ciekawego mi nie powiedziało. ;)

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline koirat

  • Użytkownik

# Listopad 07, 2013, 00:00:29
Da sie używać unsafe w unity, zauważ że nawet OpenCVSharp z niego korzysta, (niewiem czy przypadkiem nie trzeba mieć wersji pro).

W pierwszej kolejności sprawdź sobie czy to "displayImg[i, j]" jest wąskim gardłem czy SetPixel.
Jeśli SetPixel to możesz spróbować jeszcze funkcje SetPixels gdzie podajesz tablice kolorów.

Ale szczerze to nie liczył bym na przekopiowaniu obrazu HD pixel po pixelu w satysfakcjonującym czasie poprzez dwa wrappery.
« Ostatnia zmiana: Listopad 07, 2013, 00:02:21 wysłana przez koirat »

Offline Veldrin

  • Użytkownik

  • +1
# Listopad 07, 2013, 02:05:10
Zrównoleglić?

Offline koirat

  • Użytkownik

# Listopad 07, 2013, 03:36:57
Unity API nie jest thread-safe.
Dodatkowo nie wiadomo czy IplImage[,] jest.

Offline Ivian

  • Użytkownik
    • Ivian's Cave

  • +1
# Listopad 07, 2013, 10:35:02
private Color32 color;

void IplImageToTexture2D (IplImage displayImg)
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
             color.r = displayImg[i, j].Val2;
             color.g = displayImg[i, j].Val1;
             color.b = displayImg[i, j].Val0);
            videoTexture.SetPixel(j, height - i - 1, color);
        }
    }
    videoTexture.Apply();
}

Cytuj
Color32 can be implicitly converted to and from Color.

Nanooptymalizacja[brak dzielenia, rzutowania, new] zawsze spoko. Uruchom profiler z depth profiling.

Dodatkowo tak jak pisał koriat polecam SetPixels();
« Ostatnia zmiana: Listopad 07, 2013, 10:38:09 wysłana przez Ivian »

Offline Xender

  • Użytkownik

# Listopad 07, 2013, 10:41:08
Zrównoleglić?
Operacje na pamięci?

Offline Guzik

  • Użytkownik
    • Insalgo | Aplikacje mobilne, WWW, Elektronika

# Listopad 07, 2013, 13:41:02
Jeśli masz pro to pisz w unmanaged.

Offline revo

  • Użytkownik

# Listopad 07, 2013, 22:38:44
Tak jak już Ivian napisał, profiluj.

Dodatkowo zastanawiałbym się jak konwersja Color -> Color32 została zaimplementowana (jeśli pod spodem jest dzielenie to zysk mały). Można poeksperymentować z LUT do konwersji byte -> float, ale i tak wszystkie zmiany wymagają dokładnego zmierzenia wydajności ;)