Avatar
Petr Nymsa
Redaktor
Avatar
Petr Nymsa:

Ahoj, mám menší problém s voláním Dispatcher.Be­ginInvoke(), který slouží pro (dle mého velice zjednodušeného vyjádření :D) pro "napojení" zpět na main UI thread pro aktualizaci komponent z jiných vláken. Následující příklad funguje jak má

  double p = 0;
            await Task.Run(() =>
            {
                #region a
                for (double i = 0; i < 100; i++)
                {
                    for (double x = 0; x < 10; x++)
                    {
                        double h = (x * i) + x + i * (Math.Pow(i, 2));
                        System.Diagnostics.Debug.WriteLine(","+h.ToString());
                        p++;
                        Dispatcher.BeginInvoke(() => { tb.Text = h.ToString()+ " " +p.ToString(); });
                    }

                }
};

ovšem tento příklad, kde projíždím pixel po pixel bitmapu se zavolání Dispatcheru zasekne v nekonečné smyčce, problém je, že absolutně netuším proč. viz. kód (zjednodušený, snad nebude problém ve vymazaných řádcích).

 for (int x = 0; x < wb.PixelWidth && cont; x++)
                {
                    for (int y = 0; y < wb.PixelHeight && cont; y++)
                    {
                        Color c = wb.GetPixel(x, y);

                        Dispatcher.BeginInvoke(() =>
                        {
                            tb.Text = pc.ToString();
                        });

                        if ((c.R >= iR_min && c.R <= iR_max) &&
                            (c.G >= iG_min && c.G <= iG_max) &&
                            (c.B >= iB_min && c.B <= iB_max))
                        { pc++; }

                        if (pc >= reqPixels)
                            cont = false;
                    }
                }
});

Jedná se o cyklus, který zjišťuje početnost určité barvy a to i podle určité tolerance.

Někdo nějaké nápady proč se to "zacyklí" ?

Odpovědět 3.12.2013 20:09
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Redaktor
Avatar
Odpovídá na Petr Nymsa
coells:

Ahoj Zirko, nezacykli se to, ale zahltis frontu udalosti a WPF to neunese.

  1. lambda funkce nesmi odkazovat na mutable promennou pc, volas stale dokola stejnou funkci se spolecnou hodnotou
  2. kdyz zmenis property Text, vyvola se refresh vcetne mozneho measure/arrange cyklu
  3. refresh nuti posilat graficka data na pres bus a zahlti ho take

Oprava je snadna, volej dispatcher jen obcas, treba kazdych 200ms, uz to bude fungovat

 
Nahoru Odpovědět  +1 3.12.2013 22:59
Avatar
Petr Nymsa
Redaktor
Avatar
Nahoru Odpovědět 4.12.2013 7:17
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Redaktor
Avatar
Odpovídá na coells
Petr Nymsa:

Mohl by jsi mi více rozepsat problém ? Nějak tomu nerozumím 8|

Nahoru Odpovědět 4.12.2013 11:14
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Redaktor
Avatar
Odpovídá na Petr Nymsa
coells:

Který problém? :-)

Čemu přesně nerozumíš? Zahlcení fronty událostí, špatné výkonnosti nebo špatnému použití lambda funkce?

 
Nahoru Odpovědět 4.12.2013 12:21
Avatar
Odpovídá na Petr Nymsa
Luboš Běhounek (Satik):

Jinak pokud v C# něco děláš s pixely bitmapy a nechceš čekat věčnost, tak doporučuji nepoužívat getpixel, ale převést si to na pole a procházet pak to, je to pak mnohem (třeba i až o dva řády - 100x) rychlejší.

Např. čtení takto:

UInt32[] data = new UInt32[bmp.Size.Width * bmp.Size.Height];
BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Size.Width, bmp.Size.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

unsafe
{
    fixed (UInt32* pArray = data)
    {
        IntPtr intPtr = new IntPtr((void*)pArray);
        CopyMemory(intPtr, bd.Scan0, bmp.Size.Width * bmp.Size.Height * 4);
    }
}

bmp.UnlockBits(bd);

Pixely pak máš načtené v poli data (myslím, že by neměl být problém místo UInt32 použít i Color).

A pokud používáš MSVS, tak musíš v nastavení projektu povolit unsafe code (properties projektu -> záložka Build).

V případě zájmu sem můžu odit i rychlý kód, co používám k zápisu do bitmapy.

Nahoru Odpovědět 4.12.2013 12:37
:)
Avatar
coells
Redaktor
Avatar
Odpovídá na Luboš Běhounek (Satik)
coells:

U toho řešení ale musíš vědět, v jakém formátu je bitmapa - 32bpc, 24bpc, ...

 
Nahoru Odpovědět 4.12.2013 12:48
Avatar
Odpovídá na coells
Luboš Běhounek (Satik):

Jj, já to používal v http://www.itnetwork.cz/…-magickeleto , kde jsme všechnu grafiku dělali v 32bpp.

Pokud by to chtěl použít na jiné bpp, musel by obrázek převádět před tímhle kódem do 32bpp nebo upravit ten kód (osobně bych asi spíš obrázek převáděl na 32(nebo případně 24) bpp, rozhodně je to příjemnější než pracovat s 16bpp, kde to pak musíš ručně posouvat, aby to sedělo :)

Nahoru Odpovědět 4.12.2013 13:18
:)
Avatar
Petr Nymsa
Redaktor
Avatar
Odpovídá na coells
Petr Nymsa:

Pravděpodobně všemu :D

Nahoru Odpovědět 4.12.2013 14:15
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Redaktor
Avatar
Odpovídá na Luboš Běhounek (Satik)
Petr Nymsa:

Jo díky, mrknu na to. Používám to ve WP, kde není přímo metoda GetPixel / SetPixel. Musím použít WriteableBitmap a využívám k tomu ještě knihovnu pro lepší práci.

Nahoru Odpovědět 4.12.2013 14:16
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Redaktor
Avatar
Odpovídá na Petr Nymsa
coells:

Jasně, vysvětlím to letem světem. WPF aplikace běží ve dvou vláknech:

  1. STA Main App Thread
  2. WPF Rendering Thread

Když napíšeš kód pro WPF aplikaci, to co znáš jako aplikační události, běží v hlavním vlákně, které má frontu událostí k vykonání. Každá událost má prioritu, podle které se zpracovávají. Mezi události patří například i zpracování komponent v aplikaci, kdy se rozmisťují kontrolní prvky a aplikuje se vizuální strom na základě logického stromu nebo stisknutí klávesy nebo události myši. Mimo to se výsledná data posílají na grafickou kartu, abys je viděl na monitoru.

Když uděláš ten svůj cyklus na obrázku 1000x1000, tak velice rychle vložíš 1000000 událostí do hlavního vlákna a aplikace přestane stíhat. Tímhle způsobem například zabráníš zpracování klávesnice, ale i vykreslování aplikace, protože nebudou připravena data!

WPF aplikace navíc pracují na 30 nebo 60 FPS, takže takhle rychlá aktualizace hodnot nemá žádný smysl - jenom nutíš procesor a gafickou kartu, aby pracovaly "naprázdno".

Doporučuji si koupit jednu z těchto knížek, před lety se mi moc osvědčily:

  1. WPF Unleashed
  2. Essentials WPF

Druhou chybu máš v tomhle kódu:

Dispatcher.BeginInvoke(() => { tb.Text = pc.ToString(); });

Aby to fungovalo tak, jak chceš, musíš do lambda funkce vkládat pouze imutabilní hodnoty. Takhle už je to správně:

string str = pc.ToString();
Dispatcher.BeginInvoke(() => { tb.Text = str; });
 
Nahoru Odpovědět  +1 4.12.2013 16:11
Avatar
Petr Nymsa
Redaktor
Avatar
Odpovídá na coells
Petr Nymsa:

Super, díky za stručné vysvětlení :)

Nahoru Odpovědět 4.12.2013 16:17
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
coells
Redaktor
Avatar
Odpovídá na Petr Nymsa
coells:

Promin, rad bych to rozepsal vice, ale je toho strasne moc.
Ale ty dve knizky jsou fakt super, hlavne Essentials WPF je primo od jednoho z autoru WPF, takze vysvetluje veci, co nikdo jiny.

 
Nahoru Odpovědět 4.12.2013 16:23
Avatar
Petr Nymsa
Redaktor
Avatar
Odpovídá na coells
Petr Nymsa:

V pořádku, já to myslel zcela kladně. Zaměřím se na to trošku. S WPF, respektive s XAML aplikacemi (Windows 8, Windows Phone) pracuju už delší dobu a doteď jsem to používal stejným způsobem. Bohužel a vlastně i naštěstí jsem zjistil až teď, že ne vše funguje tak jak jsem si představoval :)

Nahoru Odpovědět 4.12.2013 16:26
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Petr Nymsa
Redaktor
Avatar
Odpovídá na Luboš Běhounek (Satik)
Petr Nymsa:

Měl bych otázku. Ve Windows Phone není dostupná třída BitmapData, co tak čtu vše se točí okolo třídy WriteableBitmap. Mám následující kód

 int[] pixels = wb.Pixels;

   for (int i = 0; i < pixels.Length; i++)
   {
      Color c = new Color();
      byte[] values = BitConverter.GetBytes(pixels[i]);

      if (!BitConverter.IsLittleEndian)
          Array.Reverse(values);
      c.R = values[2];
      c.G = values[1];
      c.B = values[0];
      c.A = 255;
}

Jde to nějak urychlit ? Tohle je taky pomalý. A potřebuji právě získávat pixel po pixelu - diagnostika procentuální zastoupení barev v daném obrázku.

Nahoru Odpovědět 4.12.2013 18:54
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
martinsakra
Redaktor
Avatar
Odpovídá na Petr Nymsa
martinsakra:

http://www.codeproject.com/…-with-Csharp?… mrkni na tohle, nevim jestli to na WP pojede,ale na desktopu to funguje dobře

Nahoru Odpovědět 4.12.2013 19:50
Democracy is two wolves and a lamb voting on what to have for lunch. Liberty is a well-armed lamb contesting the vote.
Avatar
Odpovídá na Petr Nymsa
Luboš Běhounek (Satik):

S WP jsem nikdy nedělal, takže tam to neznám.

Zkoušel bych to přes vlastnost BackBuffer, to bude nejspíš ukazatel na surová data.

Nahoru Odpovědět 4.12.2013 19:52
:)
Avatar
Petr Nymsa
Redaktor
Avatar
Odpovídá na martinsakra
Petr Nymsa:

To je právě to, ve WP není přístupný BitmapData

Nahoru Odpovědět 4.12.2013 19:56
Pokrok nezastavíš, neusni a jdi s ním vpřed
Avatar
Luboš Běhounek (Satik):

A ten Backbuffer tam je?

http://msdn.microsoft.com/…teablebitmap(v=vs.110).aspx

Nahoru Odpovědět 4.12.2013 19:58
:)
Avatar
Petr Nymsa
Redaktor
Avatar
Odpovídá na Luboš Běhounek (Satik)
Petr Nymsa:

Není :@ těším se na dobu ,kdy API budou už z větší z části podobné

Nahoru Odpovědět 4.12.2013 20:05
Pokrok nezastavíš, neusni a jdi s ním vpřed
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 20 zpráv z 20.