szybka konwersja bajtów na floaty

0

Mamy obrazek z bajtów, np.: 1000x1000 i jeszcze razy 3 kolory, w 3 miliony liczb 0..255;

I ja to chcę przepisać błyskawicznie do tablicy float, o tak:

uint8 A[1000 x 3 x 1000]; // obrazek rgb

float B[1000][1000*3]; // a to jest wersja float

for i,j = n,m; ... ; ij++ ) B[i,j] = A[i,j]; // jakoś tak można to przewalić na piechotę 

ale z tego co widzę takie kopiowanie jest straszliwie wolne.

2

Ale po co chcesz to zrobić? Jaki jest twój cel (a nie rozwiązanie)?

Na pierwszy rzut oka, wygląda na to, że może ci się przydać OpenCV

1

Koniecznie to cpp musi być? Bo jak masz coś związane z przetwarzaniem obrazu, to Python prostszy, choć jego libki są głownie pisane w C/C++ :P.

5

twój cel jest taki, że na bajtach nie obliczamy obrazków, np. a[i,j] / 3 byłoby straszliwie zaokrąglone, a na floatach mniej - jasne?

jasne jest tyko tyle, że przy tak sformułowanym pytaniu, nie ma miejsca na jakiekolwiek optymalizacje.
Jedynym sposobem przepisania tablicy do innego typu jest jej przepisanie.

Gdyby było jasne, co właściwie robisz, jaki problem rozwiązujesz, to wtedy można rozważyć rożne optymalizace typu:

  • lazy evaluation
  • pieszy krok obliczań przeprowadzić na wartościach całkowitych
  • wykonywać sprytnie obliczenia na typach całkowitych
  • użyć openCV/OpenCL/CUDA (wtedy za konwersje może odpowiadać karta graficzna lub funkcje, które lepiej wykorzystają dostępny hardware)
  • .....
0

Może być... pokaż jak to działa na przykładzie:

  • mamy obrazek 1000x1000 rgb,
  • mnożymy go przez filtr ala gauss, np. 123454321 po x i po y,
  • finalnie otrzymujemy z powrotem obrazek o pierwotnej postaci, znaczy bajtowej, który można zapisać do bmp.
0

a potrafi to mnożyć zwyczajne macierze?

A x Bitmap = C

// no i z powrotem:

A^-1 x C = B';

i jeszcze różnica:
DifBitmap = B - B'; // różnica
0

Jeżeli DifBitmap nie jest macierzą zerową oznacza to tylko błędy w obliczeniach liczb zmiennoprzecinkowych, lub macierz jest singularna.
Czyli takie obliczenia nie są potrzebne.

0

Bajki opowiadasz...

Opowiem dokładnej na czym polega tu problem.

W c/c++ konwersja z BYTE na float polega na zwyczajnym przepisaniu bajtu do zmiennej int32,
co dopiero potem to jest ładowane do FPU, gdzie jest robiona konwersja: int -> float;

czy to tak wygląda:

// float = bajt; w c/c++
// produkuje kod typu:
mov eax, byte
mov temp32, eax
fldi temp32
fstp sp, dword ptr float

jak widać jest to przekombinowane...

ale i tak słabo w porównaniu do odwrotnej operacji: float w bajt!

/// byte = float; // b = round(f)

	fld       dword ptr [ebx]; // ładuje float
	call      __ftol
	mov       byte ptr [esi],al

no i to jest masakra: ten głupek wywołuje funkcję do przerobienia floata na int: ftol, dla każdego bajta!

tak wygląda ta funkcja!:

ftol ->
        fstcw   temp1.w0                ; save the control word
        fwait
        mov     al, temp1.by1
        or      temp1.by1, 0Ch          ; set rounding control to chop
        fldcw   temp1
        fistp   qword ptr temp2         ; convert to 64-bit integer
        mov     temp1.by1, al
        fldcw   temp1.w0                ; restore the control word
        mov     eax, temp2.dd0          ; return LS 32 bits
        mov     edx, temp2.dd1          ;        MS 32 bits

widać teraz jaki to jest prymityw?

a poprawna konwersja float na int (w wersji z FPU) z zaokrągleniem! wygląda tak:

fld float
fstp int

ładnie się to badziewie skróciło, co nie? :)

Widać teraz różnicę, i na czym polega problem?

1
kwalifika napisał(a):

W c/c++ konwersja z BYTE na float polega na zwyczajnym przepisaniu bajtu do zmiennej int32,

A to ciekawe, bo standard IEEE-754 mówi całkowicie coś innego

Implicit conversions - cppreference.com

A prvalue of integer or unscoped enumeration type can be converted to a prvalue of any floating-point type. If the value cannot be represented correctly, it is implementation defined whether the closest higher or the closest lower representable value will be selected, although if IEEE arithmetic is supported, rounding defaults to nearest. If the value cannot fit into the destination type, the behavior is undefined. If the source type is bool, the value false is converted to zero, and the value true is converted to one.

0

Szukamy... szukamy.. jest! :
https://en.wikipedia.org/wiki/SSE4

roundps -> w sse4.1

śmiech!
40 lat potrzebowali żeby naprawić bug c - brak funkcji: int round(float)!

Tylko szkoda, że to nie działa na kompilatorach... nadal nie ma tam takiej opcji, haha!

0
kwalifika napisał(a):

W c/c++ konwersja z BYTE na float polega na zwyczajnym przepisaniu bajtu do zmiennej int32,
co dopiero potem to jest ładowane do FPU, gdzie jest robiona konwersja: int -> float;

czy to tak wygląda:

// float = bajt; w c/c++
// produkuje kod typu:
mov eax, byte
mov temp32, eax
fldi temp32
fstp sp, dword ptr float

jak widać jest to przekombinowane...

fild może przyjąć liczbę ze znakiem o rozmiarze 16, 32 lub 64 bitów. Nie ma wariantu dla 8 bitów, ani dla liczb bez znaku: https://www.felixcloutier.com/x86/fild

1

https://godbolt.org/z/voxhaW

cvtsi2ss Converts a signed doubleword integer (or signed quadword integer if operand size is 64 bits) in the “convert-from” source operand to a single-precision floating-point value in the destination operand (first operand). The “convert-from” source operand can be a general-purpose register or a memory location. The destination operand is an XMM register. The result is stored in the low doubleword of the destination operand, and the upper three doublewords are left unchanged. When a conversion is inexact, the value returned is rounded according to the rounding control bits in the MXCSR register or the embedded rounding control bits.

Wniosek prosty, autorzy kompilatora naprawdę wiedzą lepiej, więc zamiast kombinować z assemblerem, trzeba włączyć właściwe opcje kompilatora.

0

Jak wygląda obróbka grafiki w c/c++?

rgb.r = (a + b + c + d)*.25 + 0.5; // +0.5 żeby to zaokrąglić...
rgb.g = (a + b + c + d)/4.0 + 0.5;

przecież to są kpiny:
kod jest podwójnie spartaczony!: dodawanie 0.5, a potem to jest obcinane do int!

fld float
fadd half
call _______toint // to jest procedura + 40 instrukcji - dla sztuki!

// poprawna wersja:

fld float
fstp byte

// ewentualnie
movps 32floats
storebytes 32bytes

tak należało to zrobić - 20 lat temu!
0
kwalifika napisał(a):

// poprawna wersja:

fld float
fstp byte

fist/fistp (podobnie jak fild) obsługują tylko 16, 32 i 64-bitowe liczby ze znakiem: https://www.felixcloutier.com/x86/fist:fistp

tak należało to zrobić - 20 lat temu!

A nie lepsze byłoby zaoranie całego x87?

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