Twain – autodetekcja koloru

0

Witam,

Chciałbym poprosić o podpowiedź jak poradzić sobie z następującym problemem...

Napisałem prosty program do skanowania przy użyciu biblioteki DelphiTwain Kluug, algorytm skanowania wygląda tak:

Skanuje z ADF wiele stron z opcją auto-wykrywania obrazów kolorowych lub cz&b -> w OnTwainAcquire ładuje poszczególne obrazki (TBitmap) do TList żeby móc je poprzeglądać, obrócić, usunąć jakieś niepotrzebne -> Zapisuje obrobione obrazki z TList do plików.

Problem na jaki natrafiłem to jedna wartość property PixelFormat dla wszystkich obrazków mianowicie pfDevice. Bez względu na to czy w danym TBitmap jest obrazek kolorowy czy czarno-biały, nie mogę po PixelFormat wybrać obrazów kolorowych i tak je zapisać, a czarno-białe zapisać jako np bitmapa 1bitowa.

Czy jesteście w stanie podpowiedzieć mi jak można w szybki sposób ustalić czy dana bitmapa jest czarno-biała czy kolorowa?

próbowałem walczyć z DescribePixelFormat ale zwraca mi głupawe wartości, rozbieżne z rzeczywistością.

z góry dzięki i pozdrawiam

Michał

1

1 bit czarno-biały czy 8 bit skala szarości? Zresztą tak czy tak chyba i tak nie ma innego sposobu niż pojechanie pętlą z ScanLine po całym obrazku i sprawdzenie kolorów każdego piksela dla czarno białych wszystkie składowe RGB muszą mieć wartości 0 lub 255 a dla skali szarości wszystkie składowe muszą mieć tą samą wartość R = G AND G = B naturalnie pętlę przerywamy gdy natrafiamy na pierwszy niespełniający warunków piksel.

0
kAzek napisał(a):

1 bit czarno-biały czy 8 bit skala szarości? Zresztą tak czy tak chyba i tak nie ma innego sposobu niż pojechanie pętlą z ScanLine po całym obrazku i sprawdzenie kolorów każdego piksela dla czarno białych wszystkie składowe RGB muszą mieć wartości 0 lub 255 a dla skali szarości wszystkie składowe muszą mieć tą samą wartość R = G AND G = B naturalnie pętlę przerywamy gdy natrafiamy na pierwszy niespełniający warunków piksel.

Dziękuję za odpowiedź.. przepraszam, że z takim opóźnieniem reaguje, ale byłem "utopiony" w innym problemie :)

Finalnie do samego wykrycia jakiego rodzaju jest poszczególna bitmapa użyłem metod zaszytych w komponencie Twain,

procedure TTwainSource.ReadNative(Handle: TW_UINT32; var Cancel: Boolean; Paleta: integer);
var
  DibInfo: ^TBITMAPINFO;
  ColorTableSize: Integer;
  lpBits: PAnsiChar;
  DC: HDC;
  BitmapHandle: HBitmap;
begin

  DibInfo := GlobalLock(Handle);
  ColorTableSize := (DibNumColors(DibInfo) * SizeOf(RGBQUAD));
  Paleta := PBitmapInfoHeader(DibInfo).biBitCount;
  lpBits := PAnsiChar(DibInfo);//ccc
  Inc(lpBits, DibInfo.bmiHeader.biSize);
  Inc(lpBits, ColorTableSize);
  DC := GetDC(Owner.VirtualWindow);

  BitmapHandle := CreateDIBitmap(DC, DibInfo.bmiHeader, CBM_INIT,
     lpBits, DibInfo^, DIB_RGB_COLORS);
  ReleaseDC(Owner.VirtualWindow, DC);

  Owner.DoTwainAcquire(Owner, Index, BitmapHandle, Cancel, Paleta);

  GlobalUnlock(Handle);
  GlobalFree(Handle);
end;

Pojawił się natomiast inny kłopot z którym sobie nie mogę poradzić.. mianowicie zmiana formatu Bitmapy w momencie jej zapisywania do ImageList z pfDevice na odpowiadający każdej bitmapie powoduje wzrost użycia pamięci, aż do pojawienia się komunikatu o braku miejsca w magazynie.

Stąd moja prośba.. jeśli ktoś z Was będzie w stanie wyjaśnić mi pewne zachowanie będę wdzięczny.
Mam prostą procedurę:

procedure TScanForm.ScanTwainAcquire(Sender: TObject; const Index: Integer;
  Image: TBitmap; var Cancel: Boolean; Paleta: integer);
begin

  ImageList.Add(TBitmap.Create);
  TBitmap(ImageList[ImageList.Count - 1]).Assign(Image);

  if ImageList.Count > 0 then
    begin
      if ImageList.Count = 1 then SelectFirst
       else
         if cbxShowLast.Checked then SelectLast
          else SelectFirst;
    end;

  GoForward.Enabled := ImageList.Count - 1 > CurrentImage;
  inc(LiczbaSkanow); 
  Current.Caption := Inttostr(CurrentImage + 1)+'/'+ IntToStr(LiczbaSkanow);
  Current.Repaint;
end;

za jej pomocą zapisuje do ImageList (TList) około setki obrazów ze skanera... zadziwiające jest to, że użycie pamięci nawet przy 200 obrazach kolorowych w 200dpi zajmuje w pamięci ok 20-30MB.. nie wiem jakich cudów dokonuje kompilator, ale optymalizacja działania pod tym kątem poraża...

potem mogę za pomocą kolejnej prostej procedury wyświetlać sobie zeskanowane obrazy w TImage:

procedure TScanForm.GoForwardClick(Sender: TObject);
begin
  if ImageList.Count > 0 then
   begin
     inc(CurrentImage);
     Image.Picture.Assign(TBitmap(ImageList[CurrentImage]));
   end;
end;

szybkie poruszanie się po liście i wyświetlanie obrazów także nie powoduje zwiększenia użycia RAM...
Problem pozostaje jednak, że wszystkie bitmapy mają PixelFormat = pfDevice. W zmiennej Paleta: integer przekazuję sobie głębie w bitach więc dla każdej Bitmapy moge zrobić coś takiego:

  case Paleta of
    2: TBitmap(ImageList[ImageList.Count - 1]).PixelFormat := pf1bit;
    16: TBitmap(ImageList[ImageList.Count - 1]).PixelFormat := pf4bit;
    256: TBitmap(ImageList[ImageList.Count - 1]).PixelFormat := pf8bit;
    else TBitmap(ImageList[ImageList.Count - 1]).PixelFormat := pf24bit;
  end ;

tylko niestety, każda taka operacja powoduje, że użycie pamięci także wzrasta do granicznej wartości...

Jak to jest, że zapisanie do pamięci tak dużej ilości bitmap (rekordowo zmieściłem prawie 700 skanów kolorowych w 200dpi) bez zmiany property PixelFormat, przeglądanie ich, obracanie itd powoduje, że użycie RAM jest znikome.. a wystarczy tylko zmienić PixelFormat (bez względu na jaką wartość) zabija RAM??

próbowałem wywoływać metody Dormant, FreeImage po każdej zmianie, ale nic to nie pomaga...

Będę wdzięczny za wszelkie wskazówki..

pozdrawiam

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