It is currently Mon May 25, 2020 8:54 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Floating point pixel module
PostPosted: Thu May 19, 2016 10:02 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3609
Location: Netherlands
f4 is a cross platform module to convert (part of) an image to a floating point pixel array and back.
Each pixel consists of 4 floats (rgba) with values ranging [0, 1].
For large images, it is recommended to process an image as multiple smaller blocks because each pixel takes up 16 bytes of memory.

Code:
; f4 module by Wilbert

; Supported platforms : All (Cross platform)

; CPU requirements    : SSE2 support

; Last change         : May 19, 2016


;- *** Module declaration ***

DeclareModule f4
 
  Structure rgba_f
    r.f
    g.f
    b.f
    a.f
  EndStructure
 
  Structure f4
    StructureUnion
      f.f[4]
      c.rgba_f
    EndStructureUnion
  EndStructure
 
  ; pxGet and pxSet
  ; should be called inside StartDrawing() / StopDrawing() block
  Declare pxGet(x, y, width, height, *px_f4)
  Declare pxSet(x, y, width, height, *px_f4)
 
  ; pxGetImage and pxSetImage
  ; should be called outside of StartDrawing() / StopDrawing() block
  Declare pxGetImage(Image, *px_f4)
  Declare pxSetImage(Image, *px_f4)
 
  ; low level conversion procedures
  Declare rgba2float(*px, *px_f4, num_px.l)
  Declare bgra2float(*px, *px_f4, num_px.l)
  Declare float2rgba(*px_f4, *px, num_px.l)
  Declare float2bgra(*px_f4, *px, num_px.l)
  Declare rgb2float(*px, *px_f4, num_px.l)
  Declare bgr2float(*px, *px_f4, num_px.l)
  Declare float2rgb(*px_f4, *px, num_px.l)
  Declare float2bgr(*px_f4, *px, num_px.l)
 
EndDeclareModule

;- *** Module implementation ***
Module f4
 
  DisableDebugger
  EnableExplicit
  EnableASM
 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    Macro rax:eax:EndMacro
    Macro rdx:edx:EndMacro
  CompilerEndIf
 
  Macro M_mem2xmm(arg1, arg2)
    !movups arg1, [arg2]
  EndMacro
 
  Macro M_xmm2mem(arg1, arg2)
    !movups [arg1], arg2
  EndMacro
 
  ;- ** rgb(a) to f4 conversion **
 
  Macro M_rgb2float(bgr = 0, st = 3)
    ; init xmm2, xmm3 and xmm4
    !mov eax, 0x4b004b00
    !mov ecx, 0x37800080
    !pxor xmm1, xmm1
    !movd xmm2, eax
    !movd xmm4, ecx
    !pshufd xmm2, xmm2, 0
    !pshufd xmm3, xmm2, 0
    !pshufd xmm4, xmm4, 0
    !pslld xmm3, 16
    ; load procedure arguments
    !mov ecx, [p.v_num_px]
    mov rdx, *px_f4
    mov rax, *px
    CompilerIf st = 3
      !pcmpeqd xmm5, xmm5
      !pslld xmm5, 24
    CompilerEndIf
    ; check num_px
    !sub ecx, 1
    !jz f4.rgb2float#bgr#st#_l1
    !jl f4.rgb2float#bgr#st#_l2
   
    ; handle two pixels
    !f4.rgb2float#bgr#st#_l0:
    CompilerIf st = 3
      movd xmm0, [rax]
      movd xmm1, [rax + 2]
      !psllq xmm1, 24
      !por xmm0, xmm1
      !por xmm0, xmm5
    CompilerElse
      movq xmm0, [rax] 
    CompilerEndIf
    !punpcklbw xmm0, xmm0
    CompilerIf bgr
      !pshufhw xmm1, xmm0, 11000110b
      !pshuflw xmm0, xmm0, 11000110b
    CompilerElse 
      !pshufhw xmm1, xmm0, 11100100b
    CompilerEndIf
    !punpcklwd xmm0, xmm2
    !punpckhwd xmm1, xmm2
    !subps xmm0, xmm3
    !subps xmm1, xmm3
    !mulps xmm0, xmm4
    !mulps xmm1, xmm4
    M_xmm2mem(rdx, xmm0)
    M_xmm2mem(rdx + 16, xmm1)
    add rax, st * 2
    add rdx, 32
    !sub ecx, 2
    !ja f4.rgb2float#bgr#st#_l0
    !jc f4.rgb2float#bgr#st#_l2
   
    ; handle single pixel
    !f4.rgb2float#bgr#st#_l1:   
    CompilerIf st = 3
      movzx ecx, word [rax + 1]
      !shl ecx, 8
      mov cl, [rax]
      !movd xmm0, ecx
      !por xmm0, xmm5
    CompilerElse
      movd xmm0, [rax]
    CompilerEndIf
    !punpcklbw xmm0, xmm0
    CompilerIf bgr
      !pshuflw xmm0, xmm0, 11000110b
    CompilerEndIf
    !punpcklwd xmm0, xmm2
    !subps xmm0, xmm3
    !mulps xmm0, xmm4
    M_xmm2mem(rdx, xmm0)
   
    !f4.rgb2float#bgr#st#_l2:
  EndMacro
 
  Procedure rgb2float(*px, *px_f4, num_px.l)
    M_rgb2float(0, 3)
  EndProcedure
 
  Procedure bgr2float(*px, *px_f4, num_px.l)
    M_rgb2float(1, 3)
  EndProcedure
 
  Procedure rgba2float(*px, *px_f4, num_px.l)
    M_rgb2float(0, 4)
  EndProcedure
 
  Procedure bgra2float(*px, *px_f4, num_px.l)
    M_rgb2float(1, 4)
  EndProcedure
 
  ;- ** f4 to rgb(a) conversion **
 
  Macro M_float2rgb(bgr = 0, st = 3)
    ; init xmm2
    !mov eax, 0x437f0000
    !movd xmm2, eax
    !pshufd xmm2, xmm2, 0
    ; load procedure arguments
    !mov ecx, [p.v_num_px]
    mov rax, *px_f4
    mov rdx, *px
    ; check num_px
    !sub ecx, 1
    !jz f4.float2rgb#bgr#st#_l1
    !jl f4.float2rgb#bgr#st#_l2
   
    ; handle two pixels
    !f4.float2rgb#bgr#st#_l0:
    M_mem2xmm(xmm0, rax)
    M_mem2xmm(xmm1, rax + 16)
    !mulps xmm0, xmm2
    !mulps xmm1, xmm2
    !cvtps2dq xmm0, xmm0
    !cvtps2dq xmm1, xmm1
    CompilerIf bgr
      CompilerIf st = 3
        !pshufd xmm0, xmm0, 00000110b
      CompilerElse
        !pshufd xmm0, xmm0, 11000110b
      CompilerEndIf
      !pshufd xmm1, xmm1, 11000110b
    CompilerElseIf st = 3
      !pshufd xmm0, xmm0, 10100100b
    CompilerEndIf
    !packssdw xmm0, xmm1
    !packuswb xmm0, xmm0
    CompilerIf st = 3
      movd [rdx], xmm0
      !psrlq xmm0, 24
      movd [rdx + 2], xmm0
    CompilerElse
      movq [rdx], xmm0
    CompilerEndIf
    add rax, 32
    add rdx, st * 2
    !sub ecx, 2
    !ja f4.float2rgb#bgr#st#_l0
    !jc f4.float2rgb#bgr#st#_l2
   
    ; handle single pixel
    !f4.float2rgb#bgr#st#_l1:
    M_mem2xmm(xmm0, rax)
    !mulps xmm0, xmm2
    !cvtps2dq xmm0, xmm0
    CompilerIf bgr
      !pshufd xmm0, xmm0, 11000110b
    CompilerEndIf
    !packssdw xmm0, xmm0
    !packuswb xmm0, xmm0
    CompilerIf st = 3
      !movd ecx, xmm0
      mov [rdx], cx
      !shr ecx, 16
      mov [rdx + 2], cl
    CompilerElse
      movd [rdx], xmm0
    CompilerEndIf
   
    !f4.float2rgb#bgr#st#_l2:
  EndMacro
 
  Procedure float2rgb(*px_f4, *px, num_px.l)
    M_float2rgb(0, 3)
  EndProcedure
 
  Procedure float2bgr(*px_f4, *px, num_px.l)
    M_float2rgb(1, 3)
  EndProcedure
 
  Procedure float2rgba(*px_f4, *px, num_px.l)
    M_float2rgb(0, 4)
  EndProcedure
 
  Procedure float2bgra(*px_f4, *px, num_px.l)
    M_float2rgb(1, 4)
  EndProcedure
 
  DisableASM
  Prototype _conv_proc(*src, *dst, num_px.l)
 
  ;- ** pxGet & pxSet **
 
  Procedure pxGet(x, y, width, height, *px_f4)
   
    Protected conv_proc._conv_proc
    Protected.i db, dp, pb, pf, w, h, px_f4_step
   
    w = OutputWidth() : h = OutputHeight()
    db = DrawingBuffer() : dp = DrawingBufferPitch()
    pb = OutputDepth() >> 3 : pf = DrawingBufferPixelFormat()
    Select pf & ~#PB_PixelFormat_ReversedY
      Case #PB_PixelFormat_24Bits_BGR
        conv_proc = @bgr2float()
      Case #PB_PixelFormat_32Bits_BGR
        conv_proc = @bgra2float()
      Case #PB_PixelFormat_24Bits_RGB
        conv_proc = @rgb2float()
      Default
        conv_proc = @rgba2float()
    EndSelect
    If pf & #PB_PixelFormat_ReversedY
      db + dp * h - dp
      dp = -dp
    EndIf
   
    px_f4_step = width << 4
    If x < 0 : *px_f4 - x << 4 : width + x : EndIf
    If y < 0 : *px_f4 - y * px_f4_step : height + y : EndIf
    If x > 0 : db + x * pb : w - x : EndIf
    If y > 0 : db + y * dp : h - y : EndIf
    If width > w : width = w : EndIf
    If height > h : height = h : EndIf
   
    If width > 0
      While height > 0
        conv_proc(db, *px_f4, width)
        db + dp
        *px_f4 + px_f4_step
        height - 1
      Wend
    EndIf
   
  EndProcedure
 
  Procedure pxSet(x, y, width, height, *px_f4)
   
    Protected conv_proc._conv_proc
    Protected.i db, dp, pb, pf, w, h, px_f4_step
   
    w = OutputWidth() : h = OutputHeight()
    db = DrawingBuffer() : dp = DrawingBufferPitch()
    pb = OutputDepth() >> 3 : pf = DrawingBufferPixelFormat()
    Select pf & ~#PB_PixelFormat_ReversedY
      Case #PB_PixelFormat_24Bits_BGR
        conv_proc = @float2bgr()
      Case #PB_PixelFormat_32Bits_BGR
        conv_proc = @float2bgra()
      Case #PB_PixelFormat_24Bits_RGB
        conv_proc = @float2rgb()
      Default
        conv_proc = @float2rgba()
    EndSelect
    If pf & #PB_PixelFormat_ReversedY
      db + dp * h - dp
      dp = -dp
    EndIf
   
    px_f4_step = width << 4
    If x < 0 : *px_f4 - x << 4 : width + x : EndIf
    If y < 0 : *px_f4 - y * px_f4_step : height + y : EndIf
    If x > 0 : db + x * pb : w - x : EndIf
    If y > 0 : db + y * dp : h - y : EndIf
    If width > w : width = w : EndIf
    If height > h : height = h : EndIf
   
    If width > 0
      While height > 0
        conv_proc(*px_f4, db, width)
        db + dp
        *px_f4 + px_f4_step
        height - 1
      Wend
    EndIf
   
  EndProcedure
 
  ;- ** pxGetImage & pxSetImage **
 
  Procedure pxGetImage(Image, *px_f4)
    If IsImage(Image) And StartDrawing(ImageOutput(Image))
      pxGet(0, 0, OutputWidth(), OutputHeight(), *px_f4)
      StopDrawing()
    EndIf
  EndProcedure
 
  Procedure pxSetImage(Image, *px_f4)
    If IsImage(Image) And StartDrawing(ImageOutput(Image))
      pxSet(0, 0, OutputWidth(), OutputHeight(), *px_f4)
      StopDrawing()
    EndIf
  EndProcedure
 
EndModule

_________________
macOS 10.15 Catalina, PB 5.71 x64


Last edited by wilbert on Thu May 19, 2016 10:07 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Floating point pixel module
PostPosted: Thu May 19, 2016 10:04 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3609
Location: Netherlands
A few examples

Code:
XIncludeFile "f4module.pbi"

; dim first rows, then columns
Dim img.f4::f4(199, 299)

For y = 0 To 199
  For x = 0 To 299
   
    img(y, x)\c\r = Sin(#PI * x / 300)
    img(y, x)\c\g = Cos(2 * #PI * y / 200)
    img(y, x)\c\b = Cos(2 * #PI * x / 300)
    img(y, x)\c\a = 1
   
  Next
Next

OpenWindow(0, 0, 0, 320, 220, "f4 module test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CanvasGadget(0, 10, 10, 300, 200)

StartDrawing(CanvasOutput(0))
f4::pxSet(0, 0, 300, 200, @img())
StopDrawing()

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow



Code:
XIncludeFile "f4module.pbi"

UseJPEGImageDecoder()

LoadImage(0, "myImage.jpg")

; dim first rows, then columns
h = ImageHeight(0)
w = ImageWidth(0)
max_y = h - 1
max_x = w - 1
Dim img.f4::f4(max_y, max_x)

; get pixels
f4::pxGetImage(0, @img())

; increase contrast
For y = 0 To max_y
  For x = 0 To max_x
   
    img(y, x)\c\r * 2.0 - 0.5
    img(y, x)\c\g * 2.0 - 0.5
    img(y, x)\c\b * 2.0 - 0.5
   
  Next
Next

; set pixels
f4::pxSetImage(0, @img())

; show result
OpenWindow(0, 0, 0, w, h, "f4 module test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ImageGadget(0, 0, 0, w, h, ImageID(0))

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow


Code:
XIncludeFile "f4module.pbi"

UseJPEGImageDecoder()

LoadImage(0, "myImage.jpg")

; dim first rows, then columns
h = ImageHeight(0)
w = ImageWidth(0)
max_y = h - 1
max_x = w - 1
Dim img.f4::f4(max_y, max_x)

; get pixels
f4::pxGetImage(0, @img())

; convert to sepia
For y = 0 To max_y
  For x = 0 To max_x
   
    r.f = img(y, x)\c\r
    g.f = img(y, x)\c\g
    b.f = img(y, x)\c\b
    img(y, x)\c\r = r * 0.393 + g * 0.769 + b * 0.189
    img(y, x)\c\g = r * 0.349 + g * 0.686 + b * 0.168
    img(y, x)\c\b = r * 0.272 + g * 0.534 + b * 0.131
   
  Next
Next

; set pixels
f4::pxSetImage(0, @img())

; show result
OpenWindow(0, 0, 0, w, h, "f4 module test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ImageGadget(0, 0, 0, w, h, ImageID(0))

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow


Code:
XIncludeFile "f4module.pbi"

UseJPEGImageDecoder()

; dim first rows, then columns
Dim img.f4::f4(199, 299)

LoadImage(0, "myImage.jpg")

StartDrawing(ImageOutput(0))
f4::pxGet(0, 0, 300, 200, @img())
For y = 0 To 199
  For x = 0 To 299
   
    r.f = img(y, x)\c\r
    g.f = img(y, x)\c\g
    b.f = img(y, x)\c\b
    img(y, x)\c\r = r * 0.393 + g * 0.769 + b * 0.189
    img(y, x)\c\g = r * 0.349 + g * 0.686 + b * 0.168
    img(y, x)\c\b = r * 0.272 + g * 0.534 + b * 0.131
   
  Next
Next
f4::pxSet(0, 0, 300, 200, @img())
StopDrawing()

OpenWindow(0, 0, 0, 300, 200, "f4 module test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ImageGadget(0, 0, 0, 300, 200, ImageID(0))

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow

Sepia conversion functions are based on a code example from JHPJHP.

_________________
macOS 10.15 Catalina, PB 5.71 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Floating point pixel module
PostPosted: Fri May 20, 2016 2:47 pm 
Offline
Enthusiast
Enthusiast

Joined: Fri Feb 24, 2012 10:19 am
Posts: 158
Hi, I have not found on internet an algorithm to recover the original colors of old photos when all the colors have turned into red.
Image

The following code improves well reddened pictures but do you have a better algorithm to get a better result?

Code:
XIncludeFile "f4module.pbi"

UseJPEGImageDecoder()

LoadImage(0, "mypicture.jpg")

; dim first rows, then columns
Dim img.f4::f4(199, 299)

h = ImageHeight(0)
w = ImageWidth(0)
max_y = h - 1
max_x = w - 1




StartDrawing(ImageOutput(0))
f4::pxGet(0, 0, 300, 200, @img())
For y = 0 To 199
  For x = 0 To 299
   
    r.f = img(y, x)\c\r
    g.f = img(y, x)\c\g
    b.f = img(y, x)\c\b
   
    ;Which algorythm to remove red color on an old photo ?
    img(y, x)\c\r = r * 0.393 + g * 0.769 + b * 0.189
    img(y, x)\c\g = g
    img(y, x)\c\b = b
   
  Next
Next
f4::pxSet(0, 0, 300, 200, @img())
StopDrawing()

; show result
OpenWindow(0, 0, 0, w, h, "f4 module test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ScrollAreaGadget(1, 0, 0, w,h, w+1000, h+1000, 30)

ImageGadget(0, 0, 0, w, h, ImageID(0))
CloseGadgetList()

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow



Thanx.

M.


Top
 Profile  
Reply with quote  
 Post subject: Re: Floating point pixel module
PostPosted: Fri May 20, 2016 3:57 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3609
Location: Netherlands
Mesa wrote:
Hi, I have not found on internet an algorithm to recover the original colors of old photos when all the colors have turned into red.
The following code improves well reddened pictures but do you have a better algorithm to get a better result?

That looks nice Mesa.
I wish I had a good answer but unfortunately I don't.
You probably need user interaction (click on a part that needs to be gray so you can detect the amount of red shift) or analyze the image data first before doing a correction.
Did the place where you found the current algorithm provide any more information ?

_________________
macOS 10.15 Catalina, PB 5.71 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Floating point pixel module
PostPosted: Fri May 20, 2016 4:52 pm 
Offline
Addict
Addict
User avatar

Joined: Sat Oct 09, 2010 3:47 am
Posts: 1617
Hi Mesa,

Have you tried PureBasic Interface to OpenCV?
- building on the results returned by wilbert's algorithm

You can write your own filter, or try one of the existing examples.
- an example that comes to mind: cv_add_subtract.pb

Visually is shows the words Add / Subtract, but with the saved image the captions are excluded.
- press the Spacebar to toggle between Add / Subtract
- save the image using the context menu

_________________

STATUS: Permanently Unavailable :: Downloads moved to My PureBasic Stuff
_________________


Top
 Profile  
Reply with quote  
 Post subject: Re: Floating point pixel module
PostPosted: Fri May 20, 2016 6:16 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Mon May 09, 2011 9:36 am
Posts: 497
Image

the old Picture enhancement software = Microsoft Digital Image Pro 10
does a pretty good job with just 1-click enhancement

i wish i knew how they did it ?

Image

_________________
 
PureBasic .... making tiny electrons do what you want !

"With every mistake we must surely be learning" - George Harrison


Top
 Profile  
Reply with quote  
 Post subject: Re: Floating point pixel module
PostPosted: Fri May 20, 2016 6:24 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3609
Location: Netherlands
Maybe some sort of Auto White Balance algorithm.

_________________
macOS 10.15 Catalina, PB 5.71 x64


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 14 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye