Problem z TImage + jpg

0

Witam, oto problem:

Wczytuję obrazek w formaci jpg i przepisuje do TBitmap:

var
  rozszez : string;
  b : TBitmap;
  j : TJpegImage;
begin                                                                     //
  odImg.Execute;                                                          //
  if odImg.FileName <> '' then
  begin
    
          b :=Tbitmap.Create;
          j := Tjpegimage.Create;
          b.Height := image.Height;
          b.width := image.Width;
          b.PixelFormat := pf24bit;
          j.LoadFromFile(odImg.FileName);
          b.assign(j);
          image.Picture.Bitmap :=b;
          b.Free;
          j.Free;
  end;
end;

Następnie bawię się kolorami:

var
r,g,b : byte;
i,j: integer;
begin
  for i := 0 to Image.height-1 do
  begin
    for j:= 0 to Image.width-1 do
    begin
      r := GetRValue(image.Picture.Bitmap.canvas.Pixels[i,j]);
      g := GetGValue(image.Picture.Bitmap.canvas.Pixels[i,j]);
      b := GetBValue(image.Picture.Bitmap.canvas.Pixels[i,j]);
     image.Picture.Bitmap.Canvas.Pixels[i,j] := RGB(b,r,g) ;
    end;
  end;
end;

Efekt:
[IMG]http://www.img-share.net/uploads/187przyklad.jpg[/IMG]
[IMG]http://www.img-share.net/uploads/164przyklad2.jpg[/IMG]

Inaczej się dzieje w przypadku gdy H > V i na odwrót.

Dlaczego przetwarza tylko część obrazka???

0

po 1. proponuje zmienic nazwe zmiennych i,j na x,y - w przypadku grafiki latwiej jest znaleŹĆ blad (przynajmniej mi).
powinno byc image.Picture.Bitmap.canvas.Pixels[j,i] a nie image.Picture.Bitmap.canvas.Pixels[i,j].

po 2. wlasciwie jak juz uzywasz tego canvasa: image.Picture.Bitmap.Canvas...
to i w petli for powinienes uzywac wielkosci: image.Picture.Bitmap.Width, image.Picture.Bitmap.Height

po 3. optymalizacja! zrob to na scalnine - bedzie duuuuuzo szybsze.
jesli nie chcesz scalnine bo np pixels Ci wystarcza, to chodziaz popraw to:

      r := GetRValue(image.Picture.Bitmap.canvas.Pixels[i,j]);
      g := GetGValue(image.Picture.Bitmap.canvas.Pixels[i,j]);
      b := GetBValue(image.Picture.Bitmap.canvas.Pixels[i,j]);

3 razy wywolujesz pixels[i,j] a to trwa!
lepiej daj jakas zmienna np

var c:TColor;
{...}
      c:=image.Picture.Bitmap.canvas.Pixels[i,j];
      r := GetRValue(c);
      g := GetGValue(c);
      b := GetBValue(c);
{...}
0

Dzięki za pomoc :)

Nie robię na scanline bo jeszcze go nie rozgryzłem (nie wiem jak wyłuskać poszczególne pixele).

Przykłady na wskaźnikach mnie nie bawią ;)

Mam takie cus:

Pobieram 3 kolejne pixele w danym wierszu:

 for i:= 0 to (Image.Picture.Bitmap.Height -1) do
    begin
      while (j < image.Picture.Bitmap.Width-3) do
        begin
            pix1 := Image.Picture.Bitmap.Canvas.Pixels[j,i];
            pix2 := Image.Picture.Bitmap.Canvas.Pixels[j+1,i];
            pix3 := Image.Picture.Bitmap.Canvas.Pixels[j+2,i];  
            j := j+3;
        end;
     end;

Jak ta ten kawałek kodu wyglądałby na scanline?

0

generalnie w scanline jest tak, ze ladujesz do tablicy caly "wiersz" (lub kolumne, sa dwie mozliwosci).
i ten wiersz sklada sie z bajtow. jest ich 3 razy wiecej (dla formatu bitmapy 24bit) niz szerokosc obrazka (po jednym bajcie na kazdy kolor rgb). kolory sa zapisane w tej kolejnosci: BGR.
czyli: BGR BGR BGR BGR....
1 bajt z tablicy to blue pierwszego pixela.
2 bajt to green pierwszego pixela
3 bajt to red pierwszego pixela
4 bajt to blue drugiego px
5 bajt to green drugiego px
itd...
moze to troche rozjasni Ci sposob korzystania ze scanline, teraz tylko przejrzyj jakies kody. z reszta na 4p w gotowcach, artykulach albo faqu powinno byc wszystko dokladnie opisane.

0

Wczytać to jeszcze pół biedy. Ale jak zapisać zmienioną linię pixeli do obrazka?
Przeglądałem wiele przykładów, ale w żadnym nie znalazłem jak zapisać dane.

var
r, g, b,: byte;
i, j: integer;
a : pbytearray;
begin
  for i := 0 to Image.Picture.Bitmap.Height - 1 do
  begin
    a := image.Picture.Bitmap.ScanLine[i];
    for j:= 0 to Image.Picture.Bitmap.width - 3 do
    begin

      r := a[j];
      b := a[j+1];
      c := a[j+2];
      a[j] := b;
      a[j+1] := r;
      a[j+2] := g;
      //image.Picture.Bitmap.ScanLine[i] := a;    <--- cannot assign read-only property
    end;
  end;
end;
0

Twoja petla nie ma prawa dzialac, zobacz jakie wartosci bedzie przyjmowac zmienna "j" w trakcie wykonywania petli.... 1,2,3,4 itd... zastanow sie teraz przez chwile do ktorych elementow tablicy bedziesz sie odwolywal....
to sie robi inaczej:

var r, g, b: byte;
    x,y:integer;
    row : pbytearray;
begin
  image1.Picture.bitmap.PixelFormat := pf24bit;
  for y := 0 to Image1.Picture.Bitmap.Height - 1 do
      begin
        row := image1.Picture.Bitmap.ScanLine[y];
        x:=0;
        while x<(image1.Picture.Bitmap.Width*3) do
              begin
              //ladujemy kolory do zmiennych
                b:=row[x];
                g:=row[x+1];
                r:=row[x+2];

                //edytujemy
                r:=255-r;
                g:=255-g;
                b:=255-b;

                //zapisujemy
                row[x]:=b;
                row[x+1]:=g;
                row[x+2]:=r;
                x:=x+3;
              end;
      end;
image1.Invalidate; //zmuszamy image do wyswietlenia bitmapy ktora sie zmienila
end;

lub jesli z jakis powodow wolisz petle for:

{...}
    for j:= 0 to Image.Picture.Bitmap.width - 3 do
    begin
      r := a[(j*3)];
      b := a[(j*3)+1];
{...}
0

Dzięki :) Zaraz będę testował czy rzeczywiście jest szybciej.

Ostatnie pytanko:

for i:= 0 to (Image1.Picture.Bitmap.Height -1) do
    begin
      while (j < image1.Picture.Bitmap.Width-5) do     //  '-' czy '*'   ?
        begin
            // wczytanie
            pix1 := Image1.Picture.Bitmap.Canvas.Pixels[j,i];
            pix2 := Image1.Picture.Bitmap.Canvas.Pixels[j+1,i];
            pix3 := Image1.Picture.Bitmap.Canvas.Pixels[j+2,i]; 
            pix4 := Image1.Picture.Bitmap.Canvas.Pixels[j+3,i];
            pix5 := Image1.Picture.Bitmap.Canvas.Pixels[j+4,i];

            // zabawa na pixelach

            // zapisanie
            Image.Picture1.Bitmap.Canvas.Pixels[j,i] := pix1;
            Image.Picture1.Bitmap.Canvas.Pixels[j+1,i] := pix2;
            Image.Picture1.Bitmap.Canvas.Pixels[j+2,i] := pix3;
            Image.Picture1.Bitmap.Canvas.Pixels[j+3,i] := pix4;
            Image.Picture1.Bitmap.Canvas.Pixels[j+4,i] := pix5;

            j := j+5;
        end;
     end;

Jak to będzie wyglądać na wskaźnikach?

Najlepiej bez procedur, funkcji i typów pomocniczych.

var
  linia: ^byte;
  i,j : integer;

begin
for i:= 0 to (Image1.Picture.Bitmap.Height -1) do
    begin
      linia := image1.Picture.Bitmap.ScanLine[i];
      j := 0;
      while (j < image.Picture.Bitmap.Width - 5) do     //  '-' czy '*'   ?
        begin
            // wczytanie zmiennych r,g,b pixel po pixelu


            // zabawa na kolorach R,G,B poszczególnych pixeli


            // zapisanie wczytanych pixeli
           
            j := j+5;
        end;
     end;
end;

??

0

Sorry za powyższy post, nie zwracaj na niego uwagi :)

Już mniej więcej wiem ocb.

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