Pobieranie "image area" i "color area" pulpitu

0

Ok teraz powinno działać pod win 32

0

@XA: coś ten Twój program nie działa zbyt dobrze, obejrzyj film z załącznika.

Nadal twierdzisz, że jest sens oszczędzać na linijkach kodu? ;)


W załączniku dodaję plik wykonywalny swojego narzędzia – pobaw się.

Z nudów – czekając na Twoją wersję – dodałem u siebie kotwice do rozciągania w pionie i poziomie (oprócz diagonalnych), a także automatyczne ukrywanie tych kotwic, jeśli rozmiar zaznaczenia jest zbyt mały. Kotwice nie są też widoczne podczas przesuwania lub rozciągania zaznaczenia – aby nie przeszkadzały.

W razie gdyby nie podobała Ci się wielkość kotwic to klawiszami + i - zwiększa się je lub zmniejsza (minimum to 3 piksele, natomiast maksimum to 45 pikseli).

Edit: Obrazek znajdujący się w archiwum jest potrzebny – program używa go jako tła.

0

Skończyłem ten wcześniej zaczęty program – byłem ciekaw co mi z tego wyjdzie.

tool.png

Ramkę da się przesuwać, da się ją też rozciągać (we wszystkich kierunkach). Kursor reaguje co do piksela na kotwice oraz samą ramkę zaznaczenia, a także prawidłowo zmienia się podczas samego rozciągania ramki (w przypadku rozciągania w dwóch osiach jednocześnie). Obsługuje też zaznaczanie o szerokości lub wysokości 0px – i będąc w takim rozmiarze, daje się przesunąć.

Z takich bajerów to dodałem opcję ukrywania przycisków do rozciągania względem jednej osi, jeśli rozmiar zaznaczenia jest zbyt mały. No i zostawiłem też opcję zmiany rozmiaru kotwic klawiszami + i - – po pierwsze, aby sprawdzić poprawność działania mechanizmów przesuwania i rozciągania, ale też po to, aby móc określić odpowiedną ich wielkość dla własnych potrzeb.

Pełne źródła dla Lazarusa w załączniku, również ze skompilowanym plikiem wykonywalnym. Have fun. ;)

0

W załączniku jest kod tej procedury która mi szuka kolorów :)
Tylko się nie śmiej że taki nobowaty :(

 ko :=KodowanieKolorHtml(KoKolor);
 kp := KodowanieKolorHtml(KpKolor); 

możesz zakomentować b to tylko do "logów" wykorzystywałem

0

O rany… aleś sposób wybrał…

Masz na wejściu kod koloru (w postaci ciągu znaków), musisz znaleźć w bitmapie piksele o takim samym kolorze, co zadany. Po co w środku konwertujesz kolory na łańcuchowe kody?

0

ale za to if ładnie wygląda :P To jak to to powinno wyglądać ?

0

Masz ramkę funkcji:

function CountColorInBitmap(ABitmap: TBitmap; AR, AG, AB: UInt8): UInt32;
begin

end;

Uzupełnij ją w kod zliczający wystąpienia zadanego koloru (bez używania zmiennych globalnych).


Edit: tak przy okazji – nagłówki typów potrzebnych do iterowania po pikselach powinny wyglądać tak:

type
  TRGBTriple = packed record
    B, G, R: UInt8;
  end;

type
  PRGBTripleArr = ^TRGBTripleArr;
  TRGBTripleArr = packed array [0 .. MaxInt div SizeOf(TRGBTriple) - 1] of TRGBTriple;
0

A więc ta funkcja powinna wyglądać +- chyba tak :

function CountColorInBitmap(ABitmap: Graphics.TBitmap; AR, AG, AB: UInt8): UInt32;
var
  Skaner: PRGBTripleArr;
  Y,X,licznik: Integer;
begin
 licznik:=0;
  for Y:= 0 to ABitmap.Height - 1 do
  begin
    Skaner := ABitmap.ScanLine[Y];
    for X:= 0 to ABitmap.Width - 1 do
    begin
      with Skaner^[X] do
        begin
        if (R = AR) and (G = AG) and (B = AB) then
        	begin
    			inc(licznik);
        	end;
        end;
    end;
  end;
  Result := licznik;
end;  

Ok, a wywołanie tak (chyba) :

procedure TForm1.Button2Click(Sender: TObject);
var
   ColorT : LongInt;
   R, G, B : Byte;
begin
    Memo1.Clear;
       ColorT := ColorToRGB(Shape1.Brush.Color);
       R := GetRValue(ColorT);
       G := GetGValue(ColorT);
       B := GetBValue(ColorT);
       
// RGB()
       Memo1.Lines.Add('RGB('
         + IntToStr(R) + ','
         + IntToStr(G) + ','
         + IntToStr(B) + ')');

   //CountColorInBitmap(bmp,R,G,B);
   Memo1.Lines.Add(IntToStr(CountColorInBitmap(bmp,R,G,B)));
end; 

I co mam z tym zrobić ? :/

0

Mniej więcej dobrze, oprócz zbędnych zmiennych lokalnych i nadmiarowych bloków grupujących. W skrócie:

function CountColorInBitmap(ABitmap: Graphics.TBitmap; AR, AG, AB: UInt8): UInt32;
var
  Pixel: PRGBTripleArr;
  Y, X: Integer;
begin
  Result := 0;

  for Y := 0 to ABitmap.Height - 1 do
  begin
    Pixel := ABitmap.ScanLine[Y];
    
    for X:= 0 to ABitmap.Width - 1 do
      with Pixel^[X] do
        if (R = AR) and (G = AG) and (B = AB) then
          Result += 1;
  end;
end;

Drugi kod też nie jest zły, ale można krócej. Np. ekstrakcję składowych koloru do trzech zmiennych można zrealizować za pomocą jednej funkcji:

Graphics.RedGreenBlue(Shape1.Brush.Color, R, G, B)

Zwrócić uwagę trzeba też na to, że jeśli nie używasz systemowych kolorów (czyli np. clMenuHighlight i temu podobnych) to nie potrzebujesz korzystać z funkcji ColorToRGB – nie ma ona zastosowania w przypadku podstawowych kolorów.

Reszta w porządku, choć nie podoba mi się używanie zmiennych globalnych. Takie rzeczy opakowuje się w przyjemne klasy, a nie deklaruje byle gdzie i daje do nich dostęp zewsząd. Wyczuwam bajzel w kodzie – tak się kończy sklejanie projektu z gotowców, bez głębszego zastanowienia. Tym bardziej nabieram do tego przekonania, widząc kontrolki o domyślnych (i nic nie mówiących) nazwach.

0

Co w tym zrypałem że mi podaje złe współrzędne koloru w linijce Memo2.Lines.Add('X:'+IntToStr(X)+'Y:'+IntToStr(Y)); ?

   for Y := 0 to screen.height -1 do
  begin
    Pixel := bmp.ScanLine[Y];
    for X:= 0 to screen.width -1 do
      with Pixel^[X] do
       begin
       if (R = AR) and (G = AG) and (B = AB) then
      begin
            if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then //  obszar wybrany do skanowania ???
          begin
            Memo2.Lines.Add('X:'+IntToStr(X)+'Y:'+IntToStr(Y));
            SetCursorPos(X, koY);
            klikanie();
             break;
          end;

         end;
       end;
  end;
0

Samo przeszukiwanie bitmapy jest poprawne.

if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then //  obszar wybrany do skanowania ???

Co to za cholerstwo?

0

// współrzędne kwadratu np:
  //kp_x:=100;
  //kp_x1:=200;
 // kp_y:=100;
 // kp_y1:=200;  

//a to mi ma tylko blokować lup pokazywać w memo pozycje danego koloru na wybranym obszarze
if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then
0

Słyszałeś o czymś takim jak TRect i PtInRect? Hmm?

0

Tak! nawet go wykorzystuje do rysowania ramki :)

var
  ramka_rect : TRect;
  x,y,x2,y2,szerokosc, wysokosc: Integer;
...
 szerokosc:=x-x2;
 wysokosc:=y-y2;
...
  with ramka_rect do begin
    Left:=x;
    Top:=y;
    Right:=Left+szerokosc;
    Bottom:=Top+wysokosc;
...
  end;

Ale tu po prostu będę wszystkie x-y brał w tablice więc taka prowizorka do czasu ustalenia czemu nie działają mi prawidłowe współrzędne XY

0

Pisanie prowizorek nie ujdzie Ci na sucho. W końcu zrozumiesz dlaczego – jak opadniesz na dno globalno-proceduralnego bagna. I wtedy nie będzie łatwo poprawić tego co zchrzaniłeś, nie projektując aplikacji w należyty sposób.

Przy okazji – rekord typu TRect posiada właściwości Width i Height.

0

Tylko w czym może leżeć problem, bo zmiennej X to nigdzie nie wykorzystuję :/ a z nią mam problem że się przesuwa w prawo

0

Skoro nigdzie jej nie używasz, to po co jest zadeklarowana?

if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then

Ten warunek wygląda na skopany – kp_x1 jest zawsze większe lub równe kp_x? I tak samo z kp_y1?

0

x nigdzie poza tą funkcją, tak zawsze musi kp_x być mniejsze od kp_x1 lub równe bo jeśli równe to oznacza że ramka obejmuje 1px a jak większe to kp_x1 szerokość

0

No to skoro kp_x zawsze jest większe lub równe kp_x1 to powinieneś odwrócić kolejność tych warunków, bo wprowadzają w błąd. A tak w ogóle to powinieneś w tym przypadku skorzystać z funkcji Math.InRange i mieć czytelny zapis:

if InRange(X, kp_x, kp_x1) and InRange(Y, kp_y, kp_y1) then

Czytelny po warunkiem, że nazwiesz sensownie zmienną kp_x i pozostałe.

Teraz zauważyłem, że ten warunek znajduje się wewnątrz pętli skanującej piksele. Źle to robisz, bo nie powinieneś sprawdzać współrzędnych w tym warunku, ani nawet w żadnym innym. Powinieneś na podstawie zadanego obszaru poprawnie określić iteratory pętli i ich zakres.

Masz schemat:

schema.png

Pobierasz do pomocniczej zmiennej kolor z lewego górnego rogu bitmapy wzorca (zaznaczonej na niebiesko) i w pętli skanujesz obszar zaznaczony na żółto. Jeśli nie znajdziesz dopasowania w tym obszarze to znaczy, że bitmapa-wzorzec nie znajduje się w całości na bitmapie-tle.

0

kp_x jest zawsze mniejsze od kp_x1 lub równe a nie większe :) dla mnie kp_x jest czytelne bo przechowuje dane ze zmiennej kontener_pobierania_x :)

if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then

mam zamienić na:

      for Y := kp_y to kp_y1 do
       ...
        for X :=kp_x to kp_x1 do

czy o coś innego chodzi z zadanym obszarem?

Nie używam bitmapy wzorca a sam kolor przechowuje, który później wysyłam do tej procedury która szuka koloru

0
XA napisał(a):

kp_x jest zawsze mniejsze od kp_x1 lub równe a nie większe :) dla mnie kp_x jest czytelne bo przechowuje dane ze zmiennej kontener_pobierania_x :)

Nie, nie jest czytelne – kp_x absolutnie nic nie mówi o tej zmiennej, kontener_pobierania_x również… Znaków podkreślenia używa się wyłącznie do nazewnictwa stałych i symboli – do zmiennych używa się PascalCase.

Czytałeś kiedykolwiek Object Pascal Style Guide?

mam zamienić na:

      for Y := kp_y to kp_y1 do
       ...
        for X :=kp_x to kp_x1 do

Oczywiście – masz przeglądać wyłącznie zadany obszar, a nie całą bitmapę. Poza tym, jeśli funkcja ma znaleźć zadany piksel w bitmapie, to ma go znaleźć i nic więcej. Wszelkie cuda pokroju klikanie, SetCursorPos czy Memo2.Lines.Add należy robić gdzieś indziej, uprzednio pozyskując współrzędne piksela.

0

Znaków podkreślenia używa się wyłącznie do nazewnictwa stałych i symboli – do zmiennych używa się PascalCase.

O tym to ja nawet nie wiedziałem...

Tylko jak pozyskać te współrzędne :/ jeśli X mnie oszukuje

0

Użyj debuggera.

0

Na razie ustaliłem że jeśli program jest zbudowany w wersji "Poziom wykonywania: aslnvoker" wszystko o dziwo działa dobrze a gdy zmienię na "Poziom wykonywania: wymaga administratora " zaczyna pokazywać złe współrzędne :/ to może być spowodowane jakimś błędem w lazarusie ?

0

Że co? Ten cały poziom wykonania to po prostu jedna wartość w manifeście XML, umieszczonym w pliku wykonywalnym, więc jak miałaby oddziaływać z algorytmami, które nie są od niego uzależnione?

Już wcześniej pisałem Ci, że masz poważne braki jeśli o podstawy programowania chodzi, i że piszesz ten program kompletnie na pałę – to są powody ciągłych problemów. I będzie tylko gorzej.

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