Помогите реализовать RGB To HSV

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Помогите реализовать RGB To HSV

Сообщение v00d00911 » 12.01.2015 22:35:53

Есть код с просторов инета:
Код: Выделить всё
type
PFColor =^TFColor;//Что это не пойму
TFColor = packed record//И это....
   b,g,r: Byte;
end;

procedure RGB2HSV(Src : PFColor; Out H, S, V : Integer);
Const HSV_MAX_MUL = 360 shl 8;//это тоже не ясно что такое
Var Min, Max, Diff : Integer;
begin
H := 0; S := 0; V := 0;
If (Src.r < Src.g) and (Src.r < Src.b) then Min := Src.r else
If (Src.g < Src.b) then Min := Src.g else Min := Src.b;
If (Src.r > Src.g) and (Src.r > Src.b) then Max := Src.r else
If (Src.g > Src.b) then Max := Src.g else Max := Src.b;

Diff := Max - Min;
If (Max <> 0) and (Diff <> 0) then begin
S := ((Diff shl 8) div Max);//что за shl 8???
If S > 255 then S := 255;
If Src.r = Max then
   H := ((Src.g - Src.b) shl 8) div Diff
else If Src.g = Max then
   H := $200 + ((Src.b - Src.r) shl 8) div Diff
else
   H := $400 + ((Src.r - Src.g) shl 8) div Diff;

H := H * 60;
If H < 0 then Inc(H, HSV_MAX_MUL) else
   If H >= HSV_MAX_MUL then Dec(H, HSV_MAX_MUL);
H := H shr 8;
V := Max;
end;
end;


Не могу понять как это все работает и как его засунуть в мой проект. Знающие если Вам не трудно прокомментируйте эту процедуру.
v00d00911
новенький
 
Сообщения: 12
Зарегистрирован: 10.01.2015 20:35:11

Re: Помогите реализовать RGB To HSV

Сообщение Kitayets » 13.01.2015 12:07:27

PFColor =^TFColor;//Что это не пойму

новый тип - указатель на TFColor (типизированный указатель). Используется для того, чтобы передавалась структура TFColor в процедуру по ссылке

TFColor = packed record//И это....
b,g,r: Byte;
end;

новый тип TFColor - упакованная структура. Упакованная значит, что без выравнивания (без дыр в памяти). Медленнее обращение к компонентам структуры (может быть), но гарантирует правильность чтения/записи низкоуровневыми процедурами независимо от архитектуры (разрядность/тип ОС).

shl, shr - операторы сдвига влево/вправо. сдвиг влево соответствует умножению на 2 в степени величины сдвига, вправо - целочисленному делению. Т.е. HSV_MAX_MUL = 360 shl 8
тоже самое что SV_MAX_MUL = 360 * 2^8 = 360 * 256 = 92160

Добавлено спустя 16 минут 29 секунд:
но реализация какая-то кривая, в википедии пишется что компоненты HSV должны быть:
0<= H < 360
0<= S <=100
0<= V <=100
а тут S = [0, 255], Н до 360 (верный диапазон), V =[0, 255]. Соответственно доверия к алгоритму расчета тона тоже нет - нужно проверять.
Kitayets
постоялец
 
Сообщения: 171
Зарегистрирован: 05.05.2010 21:15:24

Re: Помогите реализовать RGB To HSV

Сообщение v00d00911 » 13.01.2015 13:32:28

Kitayets писал(а):PFColor =^TFColor;//Что это не пойму

новый тип - указатель на TFColor (типизированный указатель). Используется для того, чтобы передавалась структура TFColor в процедуру по ссылке

TFColor = packed record//И это....
b,g,r: Byte;
end;

новый тип TFColor - упакованная структура. Упакованная значит, что без выравнивания (без дыр в памяти). Медленнее обращение к компонентам структуры (может быть), но гарантирует правильность чтения/записи низкоуровневыми процедурами независимо от архитектуры (разрядность/тип ОС).

shl, shr - операторы сдвига влево/вправо. сдвиг влево соответствует умножению на 2 в степени величины сдвига, вправо - целочисленному делению. Т.е. HSV_MAX_MUL = 360 shl 8
тоже самое что SV_MAX_MUL = 360 * 2^8 = 360 * 256 = 92160

Добавлено спустя 16 минут 29 секунд:
но реализация какая-то кривая, в википедии пишется что компоненты HSV должны быть:
0<= H < 360
0<= S <=100
0<= V <=100
а тут S = [0, 255], Н до 360 (верный диапазон), V =[0, 255]. Соответственно доверия к алгоритму расчета тона тоже нет - нужно проверять.



Вот нашел другой код вроде все как и должно быть. Только теперь как этой функцией пользоваться не пойму.
Код: Выделить всё
Как конвертировать цвета RGB к HSB (HSV)

Оттенок от 0 до 360, диапазон яркости от 0 до 100 %.
При определении rgb (Красный, Зеленый, Синий) используются три целых числа (от 0 и 255 каждое)
uses math;

type
trgbcolor = record
red,
green,
blue : byte;
end;

thsbcolor = record
hue,
saturnation,
brightness : double;
end;

function rgbtohsb(rgb : trgbcolor) : thsbcolor;
var
minrgb, maxrgb, delta : double;
h , s , b : double ;
begin
h := 0.0 ;
minrgb := min(min(rgb.red, rgb.green), rgb.blue) ;
maxrgb := max(max(rgb.red, rgb.green), rgb.blue) ;
delta := ( maxrgb - minrgb ) ;
b := maxrgb ;
if (maxrgb <> 0.0) then s := 255.0 * delta / maxrgb
else s := 0.0;
if (s <> 0.0) then
begin
if rgb.red = maxrgb then h := (rgb.green - rgb.blue) / delta
else
if rgb.green = maxrgb then h := 2.0 + (rgb.blue - rgb.red) / delta
else
if rgb.blue = maxrgb then h := 4.0 + (rgb.red - rgb.green) / delta
end
else h := -1.0;
h := h * 60 ;
if h < 0.0 then h := h + 360.0;
with result do
begin
hue := h;
saturnation := s * 100 / 255;
brightness := b * 100 / 255;
end;
end;


А это мой код где нужно применить функцию
Код: Выделить всё
procedure TfMain.bScanImageClick(Sender: TObject);
//обьявляем переменные для jpeg и bmp а также переменную содержащую цвет пикселя
var
jpg: TJPEGImage;
bmp: TBitmap;
Kolor: TColor;
c:longint;
r, g, b: Byte;
begin
   jpg := Image1.Picture.Graphic as TJPEGImage;//присваиваем переменной изображение jpeg
   bmp := TBitmap.Create;//создаем пустой bmp
  try

    bmp.Width := jpg.Width;//копируем ширину изображения
    bmp.Height := jpg.Height;//копируем высоту изображения
    bmp.Canvas.Draw(0, 0, jpg);//рисуем с первого пикселя из jpg в bmp
    Kolor := bmp.Canvas.Pixels[3, 5];//получаем  цвет пикселя по координатам
c:=ColorToRGB(Kolor);
   r:= C;
   g:= C shr 8;
   b:= C shr 16;
   Как дальше перевести это дело в HSV?????   
Последний раз редактировалось v00d00911 13.01.2015 13:37:19, всего редактировалось 1 раз.
v00d00911
новенький
 
Сообщения: 12
Зарегистрирован: 10.01.2015 20:35:11

Re: Помогите реализовать RGB To HSV

Сообщение Kitayets » 13.01.2015 13:34:23

теперь как использовать ("засунуть") в твой проект:

1. создай новый unit, допустим с именем RGB2HSV - RGB2HSV.pas

внутри будет:
Код: Выделить всё
unit RGB2HSV;
interface 
type
PFColor =^TFColor;//Что это не пойму
TFColor = packed record//И это....
   b,g,r: Byte;
end;
procedure RGB2HSV(Src : PFColor; Out H, S, V : Integer);
implementation
procedure RGB2HSV(Src : PFColor; Out H, S, V : Integer);
Const HSV_MAX_MUL = 360 shl 8;//это тоже не ясно что такое
Var Min, Max, Diff : Integer;
begin
H := 0; S := 0; V := 0;
If (Src.r < Src.g) and (Src.r < Src.b) then Min := Src.r else
If (Src.g < Src.b) then Min := Src.g else Min := Src.b;
If (Src.r > Src.g) and (Src.r > Src.b) then Max := Src.r else
If (Src.g > Src.b) then Max := Src.g else Max := Src.b;

Diff := Max - Min;
If (Max <> 0) and (Diff <> 0) then begin
S := ((Diff shl 8) div Max);//что за shl 8???
If S > 255 then S := 255;
If Src.r = Max then
   H := ((Src.g - Src.b) shl 8) div Diff
else If Src.g = Max then
   H := $200 + ((Src.b - Src.r) shl 8) div Diff
else
   H := $400 + ((Src.r - Src.g) shl 8) div Diff;

H := H * 60;
If H < 0 then Inc(H, HSV_MAX_MUL) else
   If H >= HSV_MAX_MUL then Dec(H, HSV_MAX_MUL);
H := H shr 8;
V := Max;
end;
end;

2. кладешь этот юнит к себе в проект
3. добавляешь где хочешь использовать в
uses RGB2HSV;

и допустим где-нибудь в процедуре у тебя есть значения r,g,b и надо получить тон, то:
Код: Выделить всё
procedure someProcName;
var
{...}
  h,s,v: integer;
  acolor: TFColor;
begin
{...}
  acolor.r:= r; acolor.g:= g; acolor.b:= b;
  RGB2HSV(acolor^, h,s,v);
{теперь в  h должно быть значение тона}
{...}
end;
Kitayets
постоялец
 
Сообщения: 171
Зарегистрирован: 05.05.2010 21:15:24

Re: Помогите реализовать RGB To HSV

Сообщение v00d00911 » 13.01.2015 14:00:27

Kitayets Помогте пожалуйста применить другой вариант функции в сообщении за 13.01.2015 12:32:28 и использовать ее в моем коде который тоже отображен в этом сообщении.
P.S.
Как создавать модули я знаю. Просто не пойму как ее применить в моем случае.
v00d00911
новенький
 
Сообщения: 12
Зарегистрирован: 10.01.2015 20:35:11

Re: Помогите реализовать RGB To HSV

Сообщение vitaly_l » 13.01.2015 14:07:04

v00d00911
Я вам в другой ветке выслал рабочий пример с исходниками.

Вот это прочитайте и сможете легко программировать в лазарусе:
http://freepascal.ru/download/book/lazarus_osnovy/osnovy_programmirovanija_v_srede_lazarus.pdf


.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: Помогите реализовать RGB To HSV

Сообщение Kitayets » 13.01.2015 17:11:23

вот я присобачил 2 версии в один модуль немного подкрутив одно к другому.
итак у нас программа и модуль

вот код модуля:
Код: Выделить всё
unit RGB2HSV;

{$mode objfpc}{$H+}

interface

type
  PFColor = ^TFColor;

  TFColor = packed record
    b, g, r: byte;
  end;

  THSBColor = record
    hue,
    saturnation,
    brightness: double;
  end;

procedure RGB2HSV(Src: PFColor; Out H, S, V: integer);
function rgbtohsb(var rgb: TFColor): THSBColor;

implementation

uses Math;

procedure RGB2HSV(Src: PFColor; out H, S, V: integer);
const
  HSV_MAX_MUL = 360 shl 8;//это тоже не ясно что такое
var
  Min, Max, Diff: integer;
begin
  H := 0;
  S := 0;
  V := 0;
  if (Src^.r < Src^.g) and (Src^.r < Src^.b) then
    Min := Src^.r
  else
  if (Src^.g < Src^.b) then
    Min := Src^.g
  else
    Min := Src^.b;
  if (Src^.r > Src^.g) and (Src^.r > Src^.b) then
    Max := Src^.r
  else
  if (Src^.g > Src^.b) then
    Max := Src^.g
  else
    Max := Src^.b;

  Diff := Max - Min;
  if (Max <> 0) and (Diff <> 0) then
  begin
    S := ((Diff shl 8) div Max);
    if S > 255 then
      S := 255;
    if Src^.r = Max then
      H := ((Src^.g - Src^.b) shl 8) div Diff
    else if Src^.g = Max then
      H := $200 + ((Src^.b - Src^.r) shl 8) div Diff
    else
      H := $400 + ((Src^.r - Src^.g) shl 8) div Diff;

    H := H * 60;
    if H < 0 then
      Inc(H, HSV_MAX_MUL)
    else
    if H >= HSV_MAX_MUL then
      Dec(H, HSV_MAX_MUL);
    H := H shr 8;
    V := Max;
  end;
end;

function rgbtohsb(var rgb: TFColor): THSBColor;
var
  minrgb, maxrgb, delta: double;
  h, s, b: double;
begin
  h := 0.0;
  minrgb := min(min(rgb.r, rgb.g), rgb.b);
  maxrgb := max(max(rgb.r, rgb.g), rgb.b);
  delta := (maxrgb - minrgb);
  b := maxrgb;
  if (maxrgb <> 0.0) then
    s := 255.0 * delta / maxrgb
  else
    s := 0.0;
  if (s <> 0.0) then
  begin
    if rgb.r = maxrgb then
      h := (rgb.g - rgb.b) / delta
    else
    if rgb.g = maxrgb then
      h := 2.0 + (rgb.b - rgb.r) / delta
    else
    if rgb.b = maxrgb then
      h := 4.0 + (rgb.r - rgb.g) / delta;
  end
  else
    h := -1.0;
  h := h * 60;
  if h < 0.0 then
    h := h + 360.0;
  with Result do
  begin
    hue := h;
    saturnation := s * 100 / 255;
    brightness := b * 100 / 255;
  end;
end;

end.


вот код программы из которой видно, как эти функции использовать:
Код: Выделить всё
program units_test;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, RGB2HSV
  { you can add units after this };
var
  h, s, v: integer;
  aclr: TFColor;
  r: THSBColor;
begin
  aclr.r:= 100;
  aclr.g:= 125;
  aclr.b:= 255;
  RGB2HSV.RGB2HSV(PFColor(@aclr), h, s, v);
  r:= RGB2HSV.rgbtohsb(aclr);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', h,' S= ', s,' V= ', v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', r.hue:2:3,' S= ', r.saturnation:2:3,' V= ', r.brightness:2:3);
  writeln;
  aclr.r:= 255;
  aclr.g:= 125;
  aclr.b:= 100;
  r:= RGB2HSV.rgbtohsb(aclr);
  RGB2HSV.RGB2HSV(PFColor(@aclr), h, s, v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', h,' S= ', s,' V= ', v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', r.hue:2:3,' S= ', r.saturnation:2:3,' V= ', r.brightness:2:3);
  writeln;
  aclr.r:= 255;
  aclr.g:= 254;
  aclr.b:= 253;
  r:= RGB2HSV.rgbtohsb(aclr);
  RGB2HSV.RGB2HSV(PFColor(@aclr), h, s, v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', h,' S= ', s,' V= ', v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', r.hue:2:3,' S= ', r.saturnation:2:3,' V= ', r.brightness:2:3);
  writeln;
  aclr.r:= 255;
  aclr.g:= 255;
  aclr.b:= 255;
  r:= RGB2HSV.rgbtohsb(aclr);
  RGB2HSV.RGB2HSV(PFColor(@aclr), h, s, v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', h,' S= ', s,' V= ', v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', r.hue:2:3,' S= ', r.saturnation:2:3,' V= ', r.brightness:2:3);
  writeln;
  aclr.r:= 0;
  aclr.g:= 0;
  aclr.b:= 0;
  r:= RGB2HSV.rgbtohsb(aclr);
  RGB2HSV.RGB2HSV(PFColor(@aclr), h, s, v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', h,' S= ', s,' V= ', v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', r.hue:2:3,' S= ', r.saturnation:2:3,' V= ', r.brightness:2:3);
  writeln;
  aclr.r:= 1;
  aclr.g:= 1;
  aclr.b:= 1;
  r:= RGB2HSV.rgbtohsb(aclr);
  RGB2HSV.RGB2HSV(PFColor(@aclr), h, s, v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', h,' S= ', s,' V= ', v);
  writeln('R=', aclr.r, ' G=', aclr.g, ' B=', aclr.b, ' H= ', r.hue:2:3,' S= ', r.saturnation:2:3,' V= ', r.brightness:2:3);

  readln;
end.


исходя из вывода - результат второй функции (rgbtohsb) больше похож на правду

Добавлено спустя 8 минут 5 секунд:
как это использовать в вашей задаче?

1. берете пиксел, получаете его значения rgb
2. с помощью одной из этих функций получаете значение оттенка - H (0 - 360)
3. определяете в какой цвет он "попал", например, "на глаз", если 0< H <20 - красный, если 21 < H < 40 - оранжевый и т.д., полученный цвет запоминаем
4. после того как просмотрели все пиксели - мы будем знать какие цвета присутствуют на картинке.

правильно ли я понял Вашу задачу? Понятно ли мое решение?
Kitayets
постоялец
 
Сообщения: 171
Зарегистрирован: 05.05.2010 21:15:24


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 232

Рейтинг@Mail.ru
cron