Page 2 of 2

Re: Blur Optimisations

Posted: Fri May 18, 2012 8:24 am
by djes
I think of two optims :
  • To record all pondered values in a floats array (pixel color/average)
  • When you're parsing the image, you don't have to always recompute all the pixels. Just add the new ones and substract the old ones. For example, if you're going from left to right, you hast have to add the new pixels to the right, and substract the pixels from the left. All the pixels in the center haven't changed and don't need to be read and recalculated. Maybe you can create sort of a pattern with a matrix.

Re: Blur Optimisations

Posted: Fri May 18, 2012 9:48 am
by Foz
This is exactly what I've been attempting, but I haven't been successful just yet. Maybe tonight/this weekend.

Re: Blur Optimisations

Posted: Tue May 22, 2012 12:43 am
by Foz
Well, I can say that:
a) doing fast algorithms are hard :evil:
b) google makes "cheating" far to easy :twisted:

So, this is not mine!I got it from here.

I'm not going to go any further with the algorithm, if this is the fastest someone else can manage out of numerous attempts, then I'm happy with it. Unless someone actually wants me to convert the quasi-gaussian blur that is.

I have an app to finish writing and I've spent waaaay too much time on something that isn't important! (a quick blur? yeah, no problem!)

I would be ecstatic and eternally grateful if some speed wizards could help out here to make it near instantanious (here's hoping!)

Code: Select all

DisableDebugger

Structure strColorRGB
  r.a
  g.a
  b.a
EndStructure

Procedure Min(a.i, b.i)
  If a >= b
    ProcedureReturn b
  Else
    ProcedureReturn a
  EndIf
EndProcedure

Procedure Max(a.i, b.i)
  If a <= b
    ProcedureReturn b
  Else
    ProcedureReturn a
  EndIf
EndProcedure


Procedure fastblur(img.i, radius.i)
  StartDrawing(ImageOutput(img))
  If radius < 1
    ProcedureReturn
  EndIf
  
  Protected imgWidth.i = ImageWidth(img)
  Protected imgHeight.i = ImageHeight(img)
  
  Protected imgWidthMinus1.i = imgWidth - 1
  Protected imgHeightMinus1.i = imgHeight - 1
  Protected imgTotalPixels.i = imgWidth * imgHeight
  Protected div.i = radius + radius + 1
  Dim r.i(imgTotalPixels - 1)
  Dim g.i(imgTotalPixels - 1)
  Dim b.i(imgTotalPixels - 1)
  Protected yw.i
  Protected rsum.i
  Protected gsum.i
  Protected bsum.i
  Protected x.i
  Protected y.i
  Protected i.i
  Protected *pixel.strColorRGB
  Protected pixel1.i
  Protected pixel2.i
  Protected *pixel1.strColorRGB
  Protected *pixel2.strColorRGB
  Protected yp.i
  Protected yi.i
  Dim vmin.i((max(imgWidth, imgHeight)) - 1)
  Dim vmax.i((max(imgWidth, imgHeight)) - 1)
  Protected *pix = DrawingBuffer()
  Dim dv.i((256 * div) - 1)
  
  For i = 0 To (256 * div) - 1
    dv(i) = i / div
  Next
  
  yi = 0
  yw = 0
  For y = 0 To imgHeightMinus1
    bsum = 0
    gsum = 0
    rsum = 0
    For i = -radius To radius
      *pixel = *pix + (yi * 3) + (min( imgWidthMinus1, max(i, 0)) * 3 )
      
      rsum + *pixel\r
      gsum + *pixel\g
      bsum + *pixel\b
    Next
    
	For x = 0 To imgWidthMinus1
      r(yi) = dv(rsum)
      g(yi) = dv(gsum)
      b(yi) = dv(bsum)
      
      If y = 0
        vmin(x) = min(x + radius + 1, imgWidthMinus1)
        vmax(x) = max(x - radius, 0)
      EndIf
      
      *pixel1 = *pix + (yw * 3) + (vmin(x) * 3)
      *pixel2 = *pix + (yw * 3) + (vmax(x) * 3)
      
      rsum + *pixel1\r - *pixel2\r
      gsum + *pixel1\g - *pixel2\g
      bsum + *pixel1\b - *pixel2\b
      
      yi = yi + 1
    Next
    
    yw = yw + imgWidth
  Next
  
  For x = 0 To imgWidthMinus1
    bsum = 0
    gsum = 0
    rsum = 0
    
    yp = -radius * imgWidth
    
	For i = -radius To radius
      yi = max(0, yp) + x
      rsum = rsum + r(yi)
      gsum = gsum + g(yi)
      bsum = bsum + b(yi)
      yp = yp + imgWidth
    Next
    
    yi = x
    
	For y = 0 To imgHeightMinus1
      *pixel = *pix + (yi * 3)
      *pixel\r = dv( rsum )
      *pixel\g = dv( gsum )
      *pixel\b = dv( bsum )
      
      If x = 0
        vmin(y) = min(y + radius + 1, imgHeightMinus1) * imgWidth
        vmax(y) = max(y - radius, 0) * imgWidth
      EndIf
      
      pixel1 = x + vmin(y)
      pixel2 = x + vmax(y)
      
      rsum = rsum + r(pixel1) - r(pixel2)
      gsum = gsum + g(pixel1) - g(pixel2)
      bsum = bsum + b(pixel1) - b(pixel2)
      
      yi = yi + imgWidth
    Next
  Next
  StopDrawing()
EndProcedure


Procedure.i CaptureScreen(left.l, top.l, Width.l, Height.l, Blur)
  #CAPTUREBLT = $40000000
  Protected dm.DEVMODE ;structure for CreateDC() 
  Protected srcDC.l
  Protected trgDC.l
  Protected BMPHandle.l
  
  srcDC = CreateDC_ ( "DISPLAY" , "" , "" , dm)
  trgDC = CreateCompatibleDC_ (srcDC)
  BMPHandle = CreateCompatibleBitmap_ (srcDC, Width, Height)
  SelectObject_ ( trgDC, BMPHandle)
  BitBlt_ ( trgDC, 0, 0, Width, Height, srcDC, left , top, #SRCCOPY|#CAPTUREBLT )
  
  Protected rv.i = CreateImage ( #PB_Any ,Width,Height)
  StartDrawing ( ImageOutput ( rv ))
  DrawImage (BMPHandle,0,0)
  StopDrawing ()
  
  DeleteDC_ ( trgDC)
  ReleaseDC_ ( BMPHandle, srcDC)
  
  ProcedureReturn rv
EndProcedure 

FormWidth = 0
FormHeight = 0
DesktopCount = ExamineDesktops()
For i = 0 To DesktopCount-1
  If FormWidth < DesktopX(i) + DesktopWidth(i)
    FormWidth = DesktopX(i) + DesktopWidth(i)
  EndIf
  If FormHeight < DesktopY(i) + DesktopHeight(i)
    FormHeight = DesktopY(i) + DesktopHeight(i)
  EndIf
Next


img = CaptureScreen(0, 0, FormWidth, FormHeight, 2) ; blurriness radius of 2

t = ElapsedMilliseconds()
fastblur(img, 2)
t = ElapsedMilliseconds() - t

OpenWindow(0, 0, 0, FormWidth, FormHeight, "...", #PB_Window_BorderLess )
StickyWindow(0, 1)
CanvasGadget(0, 0, 0, FormWidth, FormHeight)
SetGadgetAttribute(0, #PB_Canvas_Image, ImageID(img))

StartDrawing(CanvasOutput(0))
DrawText(10, 10, Str(t))
StopDrawing()

Repeat
  Select WaitWindowEvent()
      
    Case #PB_Event_Gadget
      Select EventType()
        Case #PB_EventType_LeftClick
          Break
      EndSelect
      
  EndSelect
ForEver

Re: Blur Optimisations

Posted: Sat Oct 06, 2012 9:36 am
by Puffolino
Hi,tried to add the alpha channel, but get a dark halo effect around the pixels (see example below)...

What's wrong here?

Code: Select all

Procedure Min(a.i, b.i)
	If a >= b
		ProcedureReturn b
	Else
		ProcedureReturn a
	EndIf
EndProcedure
Procedure Max(a.i, b.i)
	If a <= b
		ProcedureReturn b
	Else
		ProcedureReturn a
	EndIf
EndProcedure
Procedure ImageBlur(img.i, radius.i)

	Structure strColorRGBA
		r.a
		g.a
		b.a
		a.a
	EndStructure

	StartDrawing(ImageOutput(img))
	If radius < 1
		ProcedureReturn
	EndIf

	Protected imgWidth.i = ImageWidth(img)
	Protected imgHeight.i = ImageHeight(img)

	Protected imgWidthMinus1.i = imgWidth - 1
	Protected imgHeightMinus1.i = imgHeight - 1
	Protected imgTotalPixels.i = imgWidth * imgHeight
	Protected div.i = radius + radius + 1
	Dim r.i(imgTotalPixels - 1)
	Dim g.i(imgTotalPixels - 1)
	Dim b.i(imgTotalPixels - 1)
	Dim a.i(imgTotalPixels - 1)
	Protected yw.i
	Protected rsum.i
	Protected gsum.i
	Protected bsum.i
	Protected asum.i
	Protected x.i
	Protected y.i
	Protected i.i
	Protected *pixel.strColorRGBA
	Protected pixel1.i
	Protected pixel2.i
	Protected *pixel1.strColorRGBA
	Protected *pixel2.strColorRGBA
	Protected yp.i
	Protected yi.i
	Dim vmin.i((max(imgWidth, imgHeight)) - 1)
	Dim vmax.i((max(imgWidth, imgHeight)) - 1)
	Protected *pix = DrawingBuffer()
	Dim dv.i((256 * div) - 1)

	For i = 0 To (256 * div) - 1
		dv(i) = i / div
	Next

	yi = 0
	yw = 0
	For y = 0 To imgHeightMinus1
		bsum = 0
		gsum = 0
		rsum = 0
		asum = 0
		For i = -radius To radius
			*pixel = *pix + (yi * 4) + (min( imgWidthMinus1, max(i, 0)) * 4 )
			rsum + *pixel\r
			gsum + *pixel\g
			bsum + *pixel\b
			asum + *pixel\a
		Next

		For x = 0 To imgWidthMinus1
			r(yi) = dv(rsum)
			g(yi) = dv(gsum)
			b(yi) = dv(bsum)
			a(yi) = dv(asum)

			If y = 0
				vmin(x) = min(x + radius + 1, imgWidthMinus1)
				vmax(x) = max(x - radius, 0)
			EndIf

			*pixel1 = *pix + (yw * 4) + (vmin(x) * 4)
			*pixel2 = *pix + (yw * 4) + (vmax(x) * 4)

			rsum + *pixel1\r - *pixel2\r
			gsum + *pixel1\g - *pixel2\g
			bsum + *pixel1\b - *pixel2\b
			asum + *pixel1\a - *pixel2\a

			yi = yi + 1
		Next

		yw = yw + imgWidth
	Next

	For x = 0 To imgWidthMinus1
		bsum = 0
		gsum = 0
		rsum = 0
		asum = 0

		yp = -radius * imgWidth

		For i = -radius To radius
			yi = max(0, yp) + x
			rsum = rsum + r(yi)
			gsum = gsum + g(yi)
			bsum = bsum + b(yi)
			asum = asum + a(yi)
			yp = yp + imgWidth
		Next

		yi = x

		For y = 0 To imgHeightMinus1
			*pixel = *pix + (yi * 4)
			*pixel\r = dv( rsum )
			*pixel\g = dv( gsum )
			*pixel\b = dv( bsum )
			*pixel\a = dv( asum )

			If x = 0
				vmin(y) = min(y + radius + 1, imgHeightMinus1) * imgWidth
				vmax(y) = max(y - radius, 0) * imgWidth
			EndIf

			pixel1 = x + vmin(y)
			pixel2 = x + vmax(y)

			rsum+ r(pixel1) - r(pixel2)
			gsum+ g(pixel1) - g(pixel2)
			bsum+ b(pixel1) - b(pixel2)
			asum+ a(pixel1) - a(pixel2)

			yi = yi + imgWidth
		Next
	Next
	StopDrawing()
EndProcedure
Procedure CreateKeyImage(image,w,h,b1,b2,b3,r1,r2,c1,c2,c3,c4)

	Protected i
	Protected bs=b1+b2
	Protected r3=bs+r2
	Protected g.f

	Enumeration
		#ImageTemp=99
		#ImageCrop
	EndEnumeration


	CreateImage(image,w,h,32|#PB_Image_Transparent)
	CreateImage(#ImageTemp,w,h,32|#PB_Image_Transparent)

	StartDrawing(ImageOutput(#ImageTemp))
	DrawingMode(#PB_2DDrawing_AllChannels)

	; Glänzende Fläche oben
	Circle(r3,r3,r2,c3)
	Circle(w-r3,r3,r2,c3)
	Box(r3,bs,w-r3<<1,b3,c3)
	Circle(r3,r3,r2-b3,#False)
	Circle(r3,r3+b3>>2,r2-b3+b3>>2,#False)
	Circle(r3+b3>>2,r3+b3>>1,r2-b3+b3>>1,#False)
	Circle(r3+b3>>1,r3+b3,r2-b3+b3,#False)
	Circle(r3+b3>>1+b3>>3,r3+b3+b3>>1,r2+b3>>2,#False)
	Circle(w-r3,r3+b3*3,r2+b3<<1,#False)
	Box(r3+b3>>1,bs+b3,w-r3<<1-b3>>1,bs,#False)
	StopDrawing()

	For i=-1 To b3>>2
		ImageBlur(#ImageTemp,2)
	Next i

	StartDrawing(ImageOutput(image))
	DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Gradient)
	BackColor(c1)
	FrontColor(c2)
	LinearGradient(0,bs,0,h-bs)
	RoundBox(b1,b1,w-b1<<1,h-b1<<1,r1-b1,r1-b1)

	DrawingMode(#PB_2DDrawing_Default)
	;DrawImage(ImageID(#ImageTemp),0,0)
	DrawAlphaImage(ImageID(#ImageTemp),0,0)
	StopDrawing()

EndProcedure
Procedure Grey(tone)

	ProcedureReturn $FF000000|tone*$10101

EndProcedure

CreateKeyImage(0,570,420,15,20,20,80,40,Grey(150),Grey(70),Grey(220),#Yellow)
OpenWindow(0,0,0,570,420,"")
ImageGadget(0,0,0,570,420,ImageID(0))

Repeat
Until WaitWindowEvent()=#WM_CHAR