logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Algorytm] - Procentowe "przeniknięcie" dwóch kolorów

mikmas 14 Cze 2016 21:32 1827 11
REKLAMA
  • #1 15743099
    mikmas
    Poziom 18  
    Posty: 611
    Pomógł: 9
    Ocena: 18
    Za bardzo nie wiedziałem jak napisać temat, także proszę wybaczyć :)

    Mam 2 kolory RGB - tło oraz to, co mam na nim namalować, ale z uwzględnieniem procentowego pokrycia (taki alphablending dla ubogich). Wszędzie są przykłady w RGBA, niestety ja mam tylko RGB (i to RGB565, ale to akurat nieważne). Przykładowo po namalowaniu pixela białego na czarnym w 50% powstanie szary. Łososiowego na czarnym - ciemniejszy łososiowy. Jak wyliczyć wartość takiego pixela?

    PS. czemu tu nie ma ogólnego działu do algorytmiki (albo nie znalazłem?)?
  • REKLAMA
  • #2 15743463
    michcior
    Poziom 30  
    Posty: 1132
    Pomógł: 159
    Ocena: 462
    Rozbij na kanały, i mieszaj proporcjonalnie kanały. Potem złóż kanały do siebie. niby proste a operacji co nie miara.
    Np, żółty to R=255, G=255 B=0. Po drugiej stronie masz czarny czyli R=0, G=0, B=0. Dajmy na to 50% czyli R=128, G=128, B=0 i wychodzi taki sobie sraczkowaty, czyli ciemny żółty.
    http://www.colorhexa.com/808000

    Inny przykład
    http://www.colorhexa.com/800080
    na
    http://www.colorhexa.com/008080
    Wychodzi
    http://www.colorhexa.com/404080

    Możesz sprawdzić na generatorach gradientu że się zgadza.
  • REKLAMA
  • #3 15743582
    mikmas
    Poziom 18  
    Posty: 611
    Pomógł: 9
    Ocena: 18
    Tak też robiłem i chyba w takim razie problem jest jednak po stronie kodu.
    może lookniecie, gdzie zrobiłem błąd (dam kompa że się durnowato machnąłem, bo kod prosty jak cep):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Wywołanie funkcji:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    *curGlyphPixel to zwykły char. Na każdy char przypadają 2 pixele (skala od 0 do 15 jak bardzo ma przenikać)
    wyświetlacz ma RGB565
    foreColor czcionka czerwona (F800)
    backColor tło dość ciemny szary (52AB).
    wynik - niektóre pixele są jakby... żółte (foty niestety nie zrobię, ale kolor jest na pewno miejscami bardzo nie taki).
    Co ciekawe przy foreColor F800 i backColor 0 litera tworzy się poprawnie, co ewidentnie wskazuje na mega trywialny problem, ale po zarwanej nocce zaczynam zapominać jak się zwę :P
  • REKLAMA
  • #4 15743734
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1460
    mikmas napisał:

    PS. czemu tu nie ma ogólnego działu do algorytmiki (albo nie znalazłem?)?


    Nie ma i myślę niestety nie będzie.
    Zobacz jaka jest większość pytań: problemy z językiem które są rozwiązane w pierwszy kartach dokumentacji, zadania z uczelni których User nawet nie umie bezbłędnie tu wpisać. Studenci "zmuszeni" dość studiów których nigdy nie chcieli i nie mają talentu, ochoty.
    Programiści mikroprocesorowi którzy uważają że MUSZĄ coś pisać nie mając ku temu podstawowych umiejętności.

    Polecałbym http://stackoverflow.com/ a zwłaszcza jego siostry http://codereview.stackexchange.com/ i http://programmers.stackexchange.com/
    choć tez skażony automatycznym systemem rankingu, ideałów nie ma.
  • REKLAMA
  • #5 15744010
    michcior
    Poziom 30  
    Posty: 1132
    Pomógł: 159
    Ocena: 462
    A mam stary swój kod. To jest z biblioteki na wyświetlacz na HY320 którą kiedyś sobie pisałem.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Jak chcesz wymieszać dwa kolory 565 to:
    1) przekonwertuj na RGB 24, (EXTGR_col16To32)
    2) wywołaj EXTGR_rgbMix2 dla każdej pary R,G,B
    3) wróć na RGB565 za pomocą makr RGB565CONVERT albo RGB565CONVERT24
  • #6 15744781
    mikmas
    Poziom 18  
    Posty: 611
    Pomógł: 9
    Ocena: 18
    @michcior
    Tylko nie za bardzo chcę korzystać z obcego kodu, a sam zrozumieć, gdzie błąd zrobiłem. Interpolacja prosta jak budowa cepa. Poza tym zrobienie "za jednym zamachem" przekształcenia na pojedyncze R, przeprowadzenia interpolacji, przekształcenia z powrotem na RGB565. Także pytanie nadal aktualne - co robię źle?
  • #7 15744796
    Samuraj
    Poziom 35  
    Posty: 2792
    Pomógł: 286
    Ocena: 616
    Nie pamiętam algorytmu ale wyglądało to u mnie tak:
    (kolor tła * (100 - współczynnik)) + (kolor czcionki * współczynnik)

    Współczynnik ma zakres o 0 do 100.
    Dla każdego koloru musisz zrobić tak samo. Jak pisał michcior musisz dane przekonwertować do formatu RGB888
  • #8 15745004
    mikmas
    Poziom 18  
    Posty: 611
    Pomógł: 9
    Ocena: 18
    Samuraj czytasz co ja napisałem? :)

    Tak jest właśnie robione.
    Co jest jednak źle w kodzie, że kolor jest błędny? Gdzie W KODZIE jest błąd?
  • #9 15745074
    michcior
    Poziom 30  
    Posty: 1132
    Pomógł: 159
    Ocena: 462
    Wiesz, trochę nie bardzo mamy głowy do treningu na cudzym kodzie. Ja nie potrzebuję ćwiczeń, mam je na co dzień. Dlatego pomagamy jak możemy, pokazując jak trzeba zrobić a Ty musisz zrozumieć jak działa twój kod. To z resztą dla twojego dobra. Nawet nie wiesz ile godzin spędzałem np na szukaniu spacji po znaku łączenia linii "\" w macro w C. Taka szkolna wpadka po to żeby dziś nie robić takiego błędu.

    A wracając do algorytmu. Jak tylko można, należy unikać obliczeń zmienno-przecinkowych, jak masz dwa pixele do obrobienia to ok, ale dziesiątki tysięcy zrobi kolosalną różnicę. Jak działa mój kod? Mnoży się bajt przez drugi bajt, zakładając że pixelLevel=0 to 0.0 a pixelLevel=255 to 1. W wyniku mnożenia otrzymujemy liczbę 16 bitową, olewamy młodsze 8 bitów i mamy piękne i szybkie jak błyskawica mnożenie przez 0.0 ... 1.0 Oczywiście dokładność jest słaba ale ten kompromis napędzał technologię DSP przez dziesiątki lat!
    Zlikwiduj ten tasiemiec w funkcji "alpha", rozbierz go na szereg linii i zmiennych najlepiej niech każda linia robi tylko jedną operację. Jak będziesz miał wynik dobry, to zacznij optymalizować i najlepiej owiń w macra. Można wtedy skończyć na jednej linii ale bardziej przejrzystej i czytelnej no i działające. Pamiętaj, że taka linia która nam się wydaje bardzo zgrabnym kawałkiem kodu, wcale nie musi być szybciej wykonywana niż kilka operacji w osobnych liniach. W zależności od procesora, kompilator i tak będzie się posiłkował się stosem, więc użycie zmiennych nie jest zamachem na wydajność.
  • #10 15908768
    mikmas
    Poziom 18  
    Posty: 611
    Pomógł: 9
    Ocena: 18
    Odkop robię, bo długą przerwę sobie zrobiłem i niedawno na nowo przysiadłem do kodu. Program już działa, ale... do końca nie wiem czemu :).

    Podejrzewam, że "coś" się dzieje z wartością double, ale nie mam pojęcia co.
    Ten fragment:
    double scale=((double)value)/15;
    rozbiłem na choinkę ifów i teraz funkcja wygląda tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Czyli zwykłe rozpisanie x/15. Zadziałało bez problemów.
    Co ciekawe chcąc skrócić tą oczywistą choinkę do zwykłej pętli:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    czyli nie dzielenie, a dodawanie bardzo "normalnej" wartości.
    Wynik przy pętli dostałem taki sam jak przy dzieleniu - złe kolory.
    Ktoś wie, dlaczego tak jest? Double jest dużo "bezpieczniejszy" niż float. Tym bardziej przy tak prostych liczbach i obliczeniach nie powinno mieć to większego znaczenia
  • #11 15908904
    JacekCz
    Poziom 42  
    Posty: 8670
    Pomógł: 760
    Ocena: 1460
    chyba nie rozumiesz typów. Rzutowanie na double, dzielenie przez integer (który niejawnie też jest rzutowany).
    Spostrzeżenie twoje własne "działa dziwnie" mi to potwierdza, ze to macanka na oślep.
    Dla fragmentu który podajesz, nie ma deklaracji, trudno coś powiedzieć (oprócz tego, że ładny nie jest)
  • #12 15910586
    mikmas
    Poziom 18  
    Posty: 611
    Pomógł: 9
    Ocena: 18
    Cytat:
    chyba nie rozumiesz typów. Rzutowanie na double, dzielenie przez integer (który niejawnie też jest rzutowany).

    Wiem, że jest niejawnie rzutowany

    Cytat:
    Spostrzeżenie twoje własne "działa dziwnie" mi to potwierdza, ze to macanka na oślep.

    Działa dziwnie to skrót myślowy. Kolory są kompletnie pomylone. Macanka na oślep - no nie wiem, bo "na kartce" miliony razy analizowałem tą funkcję i wyniki dawała dobre. Nie przypuszczałem, że błąd jest z wartością zmiennej scale. JTAG-a nie mam, więc się nie wepnę debugiem w kod.

    Cytat:
    Dla fragmentu który podajesz, nie ma deklaracji, trudno coś powiedzieć (oprócz tego, że ładny nie jest)

    Jest w pierwszym poście.

    Jedynym IMHO miejscem, gdzie mimo poprawnego dzielenia byłby zły kolor to przekroczenie wartości 15 (wtedy teoriatycznie mogłoby wpłynąć na inne składowe RGB). Jednak przy takim wywołaniu:
    this->PaintGlyphPixel((uint8_t)*curGlyphPixel>>4,backColor);
    this->PaintGlyphPixel((uint8_t)*curGlyphPixel&0x0F,backColor);
    gdzie *curGlyphPixel to const uint8_t *curGlyphPixel przekroczenie wartości 15 jest NIEMOŻLIWE.

Podsumowanie tematu

✨ W dyskusji poruszono problem obliczania wartości pikseli przy użyciu dwóch kolorów RGB, z uwzględnieniem procentowego pokrycia, co przypomina alpha blending. Użytkownik poszukiwał sposobu na uzyskanie poprawnych kolorów przy użyciu formatu RGB565. Odpowiedzi sugerowały rozbicie kolorów na kanały, ich proporcjonalne mieszanie oraz konwersję do formatu RGB888. Wskazano również na potencjalne błędy w kodzie, związane z rzutowaniem typów oraz obliczeniami zmiennoprzecinkowymi. Użytkownik próbował zrozumieć, gdzie popełnia błąd w swoim kodzie, który ostatecznie działał, ale kolory były niepoprawne.
Wygenerowane przez model językowy.
REKLAMA