Jak převést tři bajty RGB na jedno číslo? – Delphi – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Jak převést tři bajty RGB na jedno číslo? – Delphi – Fórum – Programujte.comJak převést tři bajty RGB na jedno číslo? – Delphi – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené.
oxidián0
Grafoman
23. 11. 2022   #1
-
0
-

var bm1: TBItmap;

...

ps0 := DWORD(bm1.scanline[0]);

Když ps0 odkazuje na první znak bitmapy, jak převést tu část RGB ze čtyřbajtového strajdu do jednoho čísla, abych mohl jednoduše porovnávat barvy mezi sebou?

Abych to ještě upřesnil. Píšu proceduru, kde je vstupní argument pFirstByte: DWord.

pFirstByte je právě ps0.

pFirstByte je uvnitř smyčky, kde je třeba spočítat aktuální hodnotu. Takže se snažím spočítat správnou hodnotu toho pointeru a ptám se, jak to tedy napsat.

type TRGBColor = Integer;

var pFirstByte:DWord;

MyColor: TRGBColor;

MyColor:= přetypovat vypočítanou pozici na integer.

Nahlásit jako SPAM
IP: 89.177.85.–
MilanL
~ Anonymní uživatel
1060 příspěvků
23. 11. 2022   #2
-
0
-

#1 oxidián
Ukazuješ moc malý kus kodu, např nevidím zda zjišťuješ formát bitmapy, nevím co za proměnnou je pixel.

Zkusil bych vyjít z této odpovědi

https://www.tek-tips.com/viewthread.cfm?qid=1076418

Pixel je tam pointer na 3bajtový typ 24bitové barvy, pokud máš 32bit je tam ještě 4. hodnota Alfa kanál.

To co děláš je blbost scanline dává pointer do paměti na daný pixel.

Pokud chceš do Pixelu barvu je třeba použít dereferenci.

Takže jednoduchá cesta je

var
   Pixel : DWORD;
   PPixel : ^DWORD;

...
   
   PPixel := bm1.scanline[0];
   Pixel := PPixel^;

v pixel by mělo zůstat 32bit číslo barvy s alfa kanálem, pak stačí pomocí AND 0x00FFFFFF a zbyde ti 24 bitů barevných složek.

V případě 24bit obrázku je nutno použít tu strukturu z odkazu, bo delphi nemá typ pro 24bitové číslo.

Nahlásit jako SPAM
IP: 185.112.167.–
MilanL
~ Anonymní uživatel
1060 příspěvků
23. 11. 2022   #3
-
0
-

#1 oxidián
používej pointery jinak ti to bude házet nesmysle.

nedopisoval jsi tem něco tu druhou 1/2 jsem dřív neviděl

Nahlásit jako SPAM
IP: 185.112.167.–
MilanL
~ Anonymní uživatel
1060 příspěvků
23. 11. 2022   #4
-
0
-

#2 MilanL

další příklad ono stačí trošku hledat (máš tam zjištění i případnou změnu včetně malého popisu formátů.

https://stackoverflow.com/questions/15297320/change-a-bitmaps-pixel-colour

Nahlásit jako SPAM
IP: 185.112.167.–
oxidián0
Grafoman
23. 11. 2022   #5
-
0
-

Udělal jsem opravu toho, že jsem napsal:

var pFirstByte:DWord;

MyColor: TRGBColor;

MyColor:= přetypovat vypočítanou pozici na integer.

Původně jsem tam pomíchal typy.

Ten první odkazovaný kód je strašný. Jako sorry, ale načítat scanline ve smyčce je strašná blbost:

for y := 0 to image1.Picture.Bitmap.Height-1 do begin
     Pixel := image1.Picture.Bitmap.Scanline[y];


Scanline je strašně pomalý a právě tomu jsem se chtěl vyhnout. Mě ale nejde o načítání celého obrazu, mě jde o to, že TRGBColor je vlastně vzorek z určitého místa v obraze. Vzorky si vybírám a ukládám do kontejneru. A chtěl jsem to uložit jako číslo. Mým cílem bylo nejprve projet celý obraz ve smyčce a získat představu jaké barvy se tam skrývají (přitom mohu udělat i analýzu, kterou využiju v dalším zpracování obrazu).

Nahlásit jako SPAM
IP: 89.177.85.–
oxidián0
Grafoman
23. 11. 2022   #6
-
0
-

"#2 MilanL
"Delfi nemá 24 bit typ..."

Nejde zkopírovat text. Te struktuře jsem se chtěl právě vyhnout. Nechci to vůbec dělit na R, G, B. Zbytečnost. Jednodušší je mít číslo 32 bit ať už v tom je maska nebo ne. Na pořadí složek mi nezáleží.

Nahlásit jako SPAM
IP: 89.177.85.–
oxidián0
Grafoman
23. 11. 2022   #7
-
0
-

Ten druhý odkaz: jemu jde o něco jiného. Chce měnit barvu pixelu. Já ale chci v proceduře nabrat výběr barev, ne je měnit. Cíl má jiný. Základní předpoklad je že k tomu nechci použít scanline, ani canvas.pixel ani to dělit na r,g,b. Ale mít to jako color: integer; Proto jsem se ptal, jak to přetypovat. Jak odkázat na 32bitů a uložit to na integer?

Nahlásit jako SPAM
IP: 89.177.85.–
gna
~ Anonymní uživatel
1891 příspěvků
23. 11. 2022   #8
-
+1
-
Zajímavé

Chce měnit barvu pixelu. Já ale chci v proceduře nabrat výběr barev, ne je měnit.

Nejdřív ho načte, pak otestuje a pak případně mění.

Jak odkázat na 32bitů a uložit to na integer?

Dostaneš obecný ukazatel, ten přetypuješ na ukazatel na 32b typ, takže dereferencí dostaneš odkazovanou 32b hodnotu. Už to Milan napsal.

Jednoduchý trik je použít ukazatel na pole, ale netuším jestli to ještě funguje.

type
  PArray32 = ^TArray32;
  TArray32 = array [0..0] of DWORD;

var
  a32: PArray32;
...
a32 := ...ScanLine[0];
{$R-}  // to pole je definovane jako 0..0, takze vypnout range check, pokud ho mas zapnuty
a32[0]
a32[1]
a32[2]
{$R+}
Nahlásit jako SPAM
IP: 213.211.51.–
oxidián0
Grafoman
23. 11. 2022   #9
-
0
-

Díky za kód. Už jsem našel řešení u profesora Davida Dirkseho.

type PDW = ^dword;
type PINT = ^integer;
...

new(pArr);
p := pFirstByte;
pArr^[1][1][1]:=PINT(p)^;


Vlastně je to very easy. Kopíruje to tu původní syntaxy s odkazem na typ dWord, jen je třeba tam přidat ten pointer nakonec :)

Nahlásit jako SPAM
IP: 89.177.85.–
gna
~ Anonymní uživatel
1891 příspěvků
23. 11. 2022   #10
-
0
-

A asi to teda je arr^[x]

Nahlásit jako SPAM
IP: 213.211.51.–
gna
~ Anonymní uživatel
1891 příspěvků
23. 11. 2022   #11
-
0
-

jj, já jsem to zrovna teď zkoušel a nevšiml jsem si, že ty už taky :)

Nahlásit jako SPAM
IP: 213.211.51.–
oxidián0
Grafoman
23. 11. 2022   #12
-
0
-

#11 gna
Mám z toho velkou radost. Já teda už v Delphi učil jsem se jednoduché věci a teď zase se učím ty pointery, tak budu umět zase něco nového.

Nahlásit jako SPAM
IP: 89.177.85.–
MilanL
~ Anonymní uživatel
1060 příspěvků
24. 11. 2022   #13
-
0
-

#9 oxidián
ale o těch pointerech jsem psal hned na začátku ten kus kodu včetně té dereference, navíc kdyby sis na netu našel scanline věděl bys, že vrací pointer a je lepší pouzívat je než přetypovávat adresy na Dword, při změně platformy pointer bude fungovat, ale dword může a nemusí.

a druhým problémem je, že při 24bitové hloubce použitím dwordu si rozhodíš barvy, je třeba použít správný formát

scanline ti vrátí adresu kde začíná 1.bod řádky a v řádce máš dle bitové hloubky pro každý pixel daný počet bajtů, tzn při 24b hloubce načtením Dwordu načteš 3B 1.pixelu + 1B 2.pixelu, při posunutí o Dword v dalším cyklu načteš 2B 2.pixelu + 2B 3.pixelu a další posun 1B 3.pixelu + 2B 4.pixelu a musel bys to pak složitě převádět.

Nahlásit jako SPAM
IP: 185.112.167.–
MilanL
~ Anonymní uživatel
1060 příspěvků
24. 11. 2022   #14
-
0
-

#13 MilanL
u posledního Dwordu má být 1B 3.pixelu a 3B 4.pixelu

Nahlásit jako SPAM
IP: 185.112.167.–
MilanL
~ Anonymní uživatel
1060 příspěvků
24. 11. 2022   #15
-
0
-

#8 gna
#9 oxidián
co se týče polí, je pak lepší pracovat s polem Bajtů nebo jednotlivým Byte  a dle hloubky načítat do  barvy daný počet bajtů

Nahlásit jako SPAM
IP: 185.112.167.–
MilanL+1
Grafoman
24. 11. 2022   #16
-
0
-

Sory za spamování, nebyl jsem na PC, kde jsem přihlášený, takže nešlo editovat.

Jinak myslím, že metoda bitmap.canvas.pixels[X,Y] to řeší efektivněji, respektive má v sobě vše ošetřeno od barevné hloubky po odpovídající načtení barvy, vrací TColor což je v podstatě DWORD..

Nahlásit jako SPAM
IP: 91.139.9.–
oxidián0
Grafoman
24. 11. 2022   #17
-
0
-

#16 MilanL
Jenže právě ta metoda canvas.pixels je velmi pomalá. Snažím se najít co nejefektivnější řešení. Zde jde jen o čtení, ale pokud by šlo o něco jiného třeba o resize nebo kernel convulsion tak jsem slyšel doporučení na lockbits jenže ten Delphi 7 nemá integrovaný v unitě Graphics. Nemá ho ani Graphics 32. Prý de dá zavolat externě na knihovnu GDI+ která je ve Windowsu, ale to řeším dvě nové otázky: a) jak to externí volání do Windows API udělat ; a 2) nebude to pomalejší než toto přetypování? Ber v potaz že počítám milisekundy a snažím se optimalizovat kód, aby jel super rychle (přesněji: aby super rychle jela potom následná funkce ať už to bude resize, kernel convulsion, nebo Sobel Edge Detection nebo nalezení bodů polygonu... Chci to maximalizovat úplně šíleně.).

V programu, který teď zpracovávám - je to jen testovací program a používá se tam TPaintBox a ten má bitmapu s 32bity. Takže ano vím jak to funguje, mám to krásně zobrazené v obrázku, načítám to... Akorád teď zrovna jsem se dostal na poslední byte strajdu a další bajt čtyři bajty mají hodnotu 0 - což nechápu. Myslel jsem že další bude první pixel prvního řádku. Každopádně mám v plánu na tu záhadu dneska přijít. Chci takto zanalyzovat celý soubor.

Nahlásit jako SPAM
IP: 94.113.182.–
oxidián0
Grafoman
24. 11. 2022   #18
-
0
-

Jo ty jsi ty pointery posílal na začátku, ale nebyl tam ten typ Integer a já to chtěl uložit do Integeru ne do DWord nebo jako pointer. A nevidím tam to přetypování jak jsem napsal v #9:

pArr^[1][1][1]:=PINT(p)^;

Proto jsem ten kód nepoužil.

Nahlásit jako SPAM
IP: 94.113.182.–
MilanL+1
Grafoman
24. 11. 2022   #19
-
0
-

#18 oxidián
DWORD a integer jsou stejně velké a můžeš je rovnou použít i v mém příkladu - velikostně jsou zaměnitelné. Rozdíl je pouze v tom že DWORD je neznaménkový v rozsahu 0....4G-1 a integer je znaménkový což určuje nejvyšší bit v rozsahu -2G...2G-1.

Pak by mělo jít i jednoduché přetypování hodnoty

císloInteger := integer(pointerDWORD^);

zítra mám volno můžu se na to kouknout.

Dále co se týče délky šířky řádku, můžeš řešit buď pomocí cyklu jako v příkladech nebo si načteš scanline další řádky a budeš porovnávat s pointerem na pixel.

Nahlásit jako SPAM
IP: 91.139.9.–
oxidián0
Grafoman
24. 11. 2022   #20
-
0
-

Tak jasně, že pomocí cyklu. Scanline kdyby to šlo bych z kódu vypustil úplně. Ale neměřil jsem fakticky jak dlouho trvá zpracování scanline a jak dlouho trvá načtení jednoho pixelu pomoci TBITMAP.canvas.pixel[x,y] . Asi bych to měl někdy změřit.

Nahlásit jako SPAM
IP: 94.113.182.–
MilanL+1
Grafoman
24. 11. 2022   #21
-
0
-

#20 oxidián
Scanline si můžeš vyzkoušet zda po skončení cyklu první řádky se pointer na další pixel rovná scanline další řádky.

Nahlásit jako SPAM
IP: 91.139.9.–
oxidián0
Grafoman
24. 11. 2022   #22
-
0
-

   

// bandWidth of TPaintBox is 4
procedure initiateSampleBuffer(xStep,yStep:byte;bandWidth:byte; pickX,pickY:byte; pFirstByte: dWord);
var stride: dWord;
    skippedStrides: dWord;
    cp: dWord; // current position in the image
    y1: dWord; // the bm1.width*bandWidth*(yStep-1)
    y2: dWord; // the bm1.width*bandWidth*yStep
    y3: dWord; // the bm1.width*bandWidth*(yStep+1)
    yCurrent: dWord;
    x1: dWord; // the y1+xStep;
    x2: dWord; // the y2+xStep;
    x3: dWord; // the y3+xStep;
    p,r: integer; // p as "position"
begin
if yStep>bm1.height/4  then
  showmessage('argument yStep is too high!');
if xStep>bm1.width/4 then
  showmessage('argument xStep is too high!');
if yStep=0  then
  showmessage('Warning: argument yStep is 0!');
if xStep=0 then
  showmessage('Warning: argument xStep is 0!');
if bandWidth<3 then
  showmessage('Bandwith not implemented! This will produce an error.');

xStep := bm1.width div xStep;
yStep := bm1.height div yStep;

stride := DWORD(bm1.width)*bandWidth;
skippedStrides := stride*yStep; // start position
new(pArr);
yCurrent := pFirstByte+skippedStrides; 
yCurrent := pFirstByte+stride-4; // poslední pixel
yCurrent := pFirstByte+stride+4; // toto měl být první pixel druhé řady
// místo červené dostávám 0

r := PINT(yCurrent)^;
showmessage(inttostr(r)); // Now debugging

Zatím se mi během toho ladění nedaří dostat ten první pixel na druhém řádku. Má červenou barvu. Černá myslím v obraze nikde není.

Nahlásit jako SPAM
IP: 94.113.182.–
MilanL+1
Grafoman
24. 11. 2022   #23
-
0
-

#22 oxidián

pokud je poslední pixel a odpovídá

yCurrent := pFirstByte+stride-4;

tak první pixel další by měl být

yCurrent := pFirstByte+stride;

EDIT:

resp spíš  yCurrent := pFirstByte+stride-3;

ještě pozor, je třeba zjistit zda je šířka width dělitelná těmi kroky, jinak nutno počítat se zbytkem.

Nahlásit jako SPAM
IP: 91.139.9.–
oxidián0
Grafoman
24. 11. 2022   #24
-
0
-

Vyzkoušel jsem všelico od +4, +64, +1024 (všechny dávaj 0. tečka.); až po

yCurrent := pFirstByte+stride+4096

a v tu chvíli to krachne. Soubor má ale velikost 912x940 tak by krachnout neměl.

Volání té moji funkce probíhá takto:

Shrnutí aktuálního problému:

Čte pouze jeden řádek. Není možné to, že scanline - jak napovídá název funkce, zpřístupní do paměti jen jeden řádek? Přitom je ale problém v tom, že já ten obrázek v GUI nevidím vykreslený. Mám poslat celý kód? Možná je chyba právě v tomto. Já to sem pošlu ať víš z čeho se skládá GUI.

unit Unit1;

{$WARN UNSAFE_CODE OFF}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, GR32_Image;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    OpenDialog1: TOpenDialog;
    PaintBox1: TPaintBox;
    PaintBox2: TPaintBox;
    Label1: TLabel;
    StaticText1: TStaticText;
    StaticText2: TStaticText;
    SaveDialog1: TSaveDialog;
    timetext: TStaticText;
    clocktext: TStaticText;
    Label2: TLabel;
    Label3: TLabel;
    Edit2: TEdit;
    Label4: TLabel;
    CheckBox1: TCheckBox;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses timerunit,resizeunit_2;

procedure TForm1.Button1Click(Sender: TObject);
//load picture
begin
 opendialog1.filter := 'bitmaps | *bmp' ;
 if opendialog1.execute then
  begin
   bm1.loadfromfile(opendialog1.filename);
   bm1.PixelFormat := pf32bit;
  end;
 with paintbox1 do
  with canvas do
   begin
    brush.color := $ffffff;
    fillrect(rect(0,0,width,height));
    draw(0,0,bm1);
   end;
 statictext1.caption := inttostr(bm1.width);
 statictext2.caption := inttostr(bm1.height);
end;

procedure TForm1.Button2Click(Sender: TObject);
//resize bm1 to bm2
var destwidth,destheight : word;
    clock1,clock2 : Int64;
begin
 destwidth := strtoint(edit1.text);
 if checkbox1.Checked then            //keep ratio
  begin
   destheight := trunc(destwidth/bm1.Width*bm1.Height);
   edit2.Text := inttostr(destheight);
  end
  else destheight := strtoint(edit2.text);
 with bm2 do
  begin
   width := destwidth;
   height := destheight;
  end;
//--
 with paintbox2 do with canvas do
  begin
   brush.color := $ffffff;
   fillrect(rect(0,0,width,height));
  end;
//--
 getCPUticks(clock1);

 // 16x16 steps should analyze (16-1)*(16-1)=225 pixels
 // 8x8 picks should analyze next (8-1)*(8-1)=49 pixels
 BMSampleResize(16,16,8,8);
 getCPUticks(clock2);
//
 timetext.Caption := formatfloat('0.0',(clock2-clock1)/CPUclock);
 paintbox2.canvas.draw(0,0,bm2);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 setCPUclock;
 clocktext.Caption := formatfloat('0.0',CPUclock);
 bm1 := Tbitmap.create;
 with bm1 do
  begin
   pixelformat := pf32bit;
   width := 200;
   height := 200;
  end;
 bm2 := Tbitmap.create;
 bm2.pixelformat := pf32bit;
 // @ For testing purposes:
 bm1.loadfromfile('U:\DELPHI\Bitmapy\TheResizeProject\resize\test.bmp');
 bm1.PixelFormat := pf32bit;
 with paintbox1 do
  with canvas do
   begin
    brush.color := $ffffff;
    fillrect(rect(0,0,width,height));
    draw(0,0,bm1);
   end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 bm1.free;
 bm2.free;
end;

end.

A unit1.dfm

object Form1: TForm1
  Left = 188
  Top = 264
  Width = 812
  Height = 612
  HorzScrollBar.Position = 38
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = True
  Position = poScreenCenter
  Scaled = False
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 378
    Top = 16
    Width = 25
    Height = 13
    Caption = 'width'
  end
  object Label2: TLabel
    Left = 610
    Top = 16
    Width = 56
    Height = 13
    Caption = 'time (usecs)'
  end
  object Label3: TLabel
    Left = 722
    Top = 16
    Width = 82
    Height = 13
    Caption = 'CPU clock (MHz)'
  end
  object Label4: TLabel
    Left = 434
    Top = 16
    Width = 29
    Height = 13
    Caption = 'height'
  end
  object PaintBox1: TPaintBox
    Left = 24
    Top = 72
    Width = 497
    Height = 489
  end
  object PaintBox2: TPaintBox
    Left = 528
    Top = 72
    Width = 265
    Height = 489
  end
  object Button1: TButton
    Left = -22
    Top = 32
    Width = 75
    Height = 25
    Caption = 'load'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 498
    Top = 32
    Width = 75
    Height = 25
    Caption = 'resize'
    TabOrder = 1
    OnClick = Button2Click
  end
  object Edit1: TEdit
    Left = 378
    Top = 32
    Width = 50
    Height = 21
    TabOrder = 2
    Text = '200'
  end
  object StaticText1: TStaticText
    Left = 66
    Top = 32
    Width = 50
    Height = 21
    AutoSize = False
    BorderStyle = sbsSunken
    Caption = '200'
    TabOrder = 3
  end
  object StaticText2: TStaticText
    Left = 138
    Top = 32
    Width = 50
    Height = 21
    AutoSize = False
    BorderStyle = sbsSunken
    Caption = '200'
    TabOrder = 4
  end
  object timetext: TStaticText
    Left = 610
    Top = 32
    Width = 97
    Height = 24
    AutoSize = False
    BorderStyle = sbsSunken
    Font.Charset = ANSI_CHARSET
    Font.Color = clBlack
    Font.Height = -16
    Font.Name = 'Arial'
    Font.Style = [fsBold]
    ParentFont = False
    TabOrder = 5
  end
  object clocktext: TStaticText
    Left = 722
    Top = 32
    Width = 81
    Height = 24
    AutoSize = False
    BorderStyle = sbsSunken
    Font.Charset = ANSI_CHARSET
    Font.Color = clBlack
    Font.Height = -16
    Font.Name = 'Arial'
    Font.Style = []
    ParentFont = False
    TabOrder = 6
  end
  object Edit2: TEdit
    Left = 434
    Top = 32
    Width = 50
    Height = 21
    TabOrder = 7
    Text = '200'
  end
  object CheckBox1: TCheckBox
    Left = 290
    Top = 32
    Width = 73
    Height = 17
    Caption = 'keep ratio'
    Checked = True
    State = cbChecked
    TabOrder = 8
  end
  object OpenDialog1: TOpenDialog
    Left = 24
    Top = 80
  end
  object SaveDialog1: TSaveDialog
    Left = 64
    Top = 80
  end
end
Nahlásit jako SPAM
IP: 94.113.182.–
oxidián0
Grafoman
24. 11. 2022   #25
-
0
-

A není to náhodou tak, že na x64 bitové architektuře by ta x32 bitová aplikace nejela, protože integer bude interpretován jako 64 bitové číslo? Netuším tedy jestli by Win32 aplikace mohla běžet pod Windows 8, 10 či 11.

Nahlásit jako SPAM
IP: 94.113.182.–
gna
~ Anonymní uživatel
1891 příspěvků
25. 11. 2022   #26
-
0
-

Integer v Delphi je vždycky 32b. Dword nejspíš taky. Ale velikosti pointerů se na 32/64 liší. To už psal Milan, že ta konverze není dobrý nápad. Ale když to budeš kompilovat jako 32b aplikaci, tak prostě bude 32b a když pak poběží na 64b systému, tak se o případné konverze postará systém.

To, že by Scanline zpřístupňovala jen jediný řádek se mi zdá nepravděpodobné.

Myslím, že Delphi obsahuje zdrojáky VCL, tak bys krokováním dovnitř Scanline měl vidět, co dělá. A i bez zdrojáků by asi měl být vidět aspoň disassemblovaný stroják a na tom taky poznáš, jestli to jen násobí šířku řádku, nebo něco čaruje.

Nebo ještě jednodušeji prostě zkusit dva různé řádky a podívat se jak se ty vrácené pointery liší. To taky už psal Milan :-)

Nahlásit jako SPAM
IP: 213.211.51.–
gna
~ Anonymní uživatel
1891 příspěvků
25. 11. 2022   #27
-
+1
-
Zajímavé

Jo, a to co jsem chtěl napsat je, že bitmapa může být uložená shora dolů nebo zdola nahoru. Nevím, co je windowsí nebo delphácký default, ale ta verze zdola nahoru by možná vysvětlovala, proč ti to padá. Tj. pokud je první řádek fyzický poslední, tak při pokusu koukat na další řádky za ním, saháš úplně mimo.

Předpokládám, že to zase půjde ověřit kouknutím na pointerý vrácené ze Scanline.

Nahlásit jako SPAM
IP: 213.211.51.–
oxidián0
Grafoman
25. 11. 2022   #28
-
0
-

Asi je to osekaná free verze D7. Když dám F7 tak neskočí do scanline

pd0 := DWORD(bm2.scanline[0]);

Dotaz k postu #8. Ten kód byl určen pro 24 bitový obrázek nebo i pro 32 bitový?

pd0 := DWORD(bm2.scanline[205]);


jede.

pd0 := DWORD(bm2.scanline[206]);


Krachne. Bitmapa 912x940 24 bit. Ale bm1.PixelFormat = pf32bit.

Já nechápu jaktože ta původní aplikace jela s PixelFormat = pf32bit a jakto, že první řádku to interpretovalo správně ty barvy pixelů.

Původní kód pro otevření souboru:

 opendialog1.filter := 'bitmaps | *bmp' ;
 if opendialog1.execute then
  begin
   bm1.loadfromfile(opendialog1.filename);
   bm1.PixelFormat := pf32bit;
  end;

Přitom ten autor programu co napsal proceduru BMresize, jemu se to načetlo a převedlo správně... Nekrachlo mu to. A s tím pointerem taky pracuje s tím přičítáním.

Nahlásit jako SPAM
IP: 94.113.182.–
MilanL+1
Grafoman
25. 11. 2022   #29
-
0
-

#27 gna

ale on má jiný problém plave v tom jak se s obrázky pracuje.

Načtený obrázek má pixelformát 24bit a on si myslí, že jednoduchou změnou toho property pixelformat ma 32bit se mu hned ten obrázek převede.

Dle mého musí provést konverzi do nové bitmapy.

Nahlásit jako SPAM
IP: 185.112.167.–
oxidián0
Grafoman
25. 11. 2022   #30
-
0
-

a ještě posílám:

// argument je natypován pFirstByte: dWord
procedure initiateSampleBuffer(xStep,yStep:byte;bandWidth:byte; pickX,pickY:byte; pFirstByte: dWord);
begin
yCurrent := pFirstByte; // neukazuje na řádek 206 ale na první bajt v obrázku... Že by protože to vůbec neukazuje na n-tý řádek obrazu?

r := PINT(yCurrent)^;
showmessage(inttostr(r));
...
end; // tady někde končí procedura
...
// VOLÁNÍ:
pd0 := DWORD(bm2.scanline[205]); // má být 206-tý řádek. Ale procedurou zpřístupním řádek 0-tý!
initiateSampleBuffer(xStep,yStep,psstep div bm1.width,xPicks,yPicks,ps0);
Nahlásit jako SPAM
IP: 94.113.182.–
gna
~ Anonymní uživatel
1891 příspěvků
25. 11. 2022   #31
-
0
-

#29 MilanL
Dokumentace vypadá, že změna formátu ta data přeformátuje. A zdá se, že mu to padá ještě před tím než by narazil na rozdíl mezi 24/32.

Nahlásit jako SPAM
IP: 213.211.51.–
gna
~ Anonymní uživatel
1891 příspěvků
25. 11. 2022   #32
-
+1
-
Zajímavé

#30 oxidián
Že 205 jede a 206 spadne je k ničemu. Podívej se na hodnoty těch pointerů.

Ten řádek máš v pd0 a voláš to s ps0. Už ten předhozí kód jsem se ani nepokoušel pochopit, protože prostě nedává smysl.

Jestli ti nějaký kód přepisem přestal fungovat, tak jsi ho prostě přepsal blbě :)

Nahlásit jako SPAM
IP: 213.211.51.–
gna
~ Anonymní uživatel
1891 příspěvků
25. 11. 2022   #33
-
+1
-
Zajímavé
Nahlásit jako SPAM
IP: 213.211.51.–
oxidián0
Grafoman
25. 11. 2022   #34
-
0
-

Hele, já v noci testoval nesprávný bmp. Sorry. Tak znova...

Nemá být pd0 := DWORD(bm2.scanline[205]);

ale ps0 := DWORD(bm1.scanline[205]);

a vyzkouším co to dělá.. Pak dám edit.

EDIT1:

Když změním barvu pixelu tak mi

r := PINT(yCurrent)^;
showmessage(inttostr(r));

vrací zápornou hodnotu. Tak teď nevím jak zobrazit kladnou hodnotu, abych to mohl převést na HEX formát a zjistit co je to za barvu.

Nahlásit jako SPAM
IP: 94.113.182.–
oxidián0
Grafoman
25. 11. 2022   #35
-
0
-

Díky za kod k unitě Graphics...

Integer(Result) := Integer(bmBits) + Row * BytesPerScanline(biWidth, biBitCount, 32);

....

function BytesPerScanline(PixelsPerScanline, BitsPerPixel, Alignment: Longint): Longint;
begin
  Dec(Alignment);
  Result := ((PixelsPerScanline * BitsPerPixel) + Alignment) and not Alignment;
  Result := Result div 8;
end;

Nahlásit jako SPAM
IP: 94.113.182.–
oxidián0
Grafoman
25. 11. 2022   #36
-
0
-

Dořešení celé te věci. Tak je to jasný. Za scanline[0] se nic nenachází, je to konec bufferu.

ps0 := DWORD(bm1.scanline[1]);.

To vrací barvy z druhého řádku. OK.

Také poslední řádek zvládne načíst:

ps0 := DWORD(bm1.scanline[939]);

V tom případě při formuli

yCurrent := pFirstByte+stride-4;

To vrací poslední barvu na posledním řádku.

Tak a teď tedy nevím jak matematicky vyřešit ten přístup přes pointery.

Nahlásit jako SPAM
IP: 94.113.182.–
MilanL+1
Grafoman
25. 11. 2022   #37
-
0
-

#36 oxidián


Tak hochu je to úplně jinak, v Image bufferu, jsou řádky uloženy pozpátku,

Ono nás v podstatě nenapadlo že vlastně v počítačové grafice je pixel 0 0 vlevo dole..

EDIT:

Takže při kontinuálním zpracování zhora stačí, když si jako první pointer natáhneš ScanLine[Height-1]

JInak koukal jsem i na tu změnu pixel formátu, tak se automaticky vytvoří nový image buffer a starý formát převede. - pozor při testování rychlosti toto přeformátování též nějaký čas zabere.

Nahlásit jako SPAM
IP: 185.112.167.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 11 hostů

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý