Image color manupilation

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
badidea
Posts: 1054
Joined: May 24, 2007 22:10
Location: The Netherlands

Image color manupilation

Postby badidea » Jun 09, 2018 11:23

For some other project I needed a way to manipulate the colors of an image in code.
So I made this. One can change brightness, contrast, gamma and gray-scale (for a certain area).
The image I used, can be found here: https://nr100.home.xs4all.nl/badidea/Ba ... ng_800.bmp (1.9 MB)
The code is not optimized for speed. Only for 32-bit images. Also room for coding style improvement...

Code: Select all

#include once "file.bi"

type xy_int
   dim as integer x, y
end type

union rgba_union
   value as ulong
   type
      b as ubyte
      g as ubyte
      r as ubyte
      a as ubyte
   end type
end union

type bitmap_header field = 1
   bfType          as ushort
   bfsize          as ulong
   bfReserved1     as ushort
   bfReserved2     as ushort
   bfOffBits       as ulong
   biSize          as ulong
   biWidth         as ulong
   biHeight        as ulong
   biPlanes        as ushort
   biBitCount      as ushort
   biCompression   as ulong
   biSizeImage     as ulong
   biXPelsPerMeter as ulong
   biYPelsPerMeter as ulong
   biClrUsed       as ulong
   biClrImportant  as ulong
end type

'===============================================================================

type image_type
   dim as any ptr pFbImg
   dim as xy_int size
   declare function create(sizeInit as xy_int, colorInit as ulong = 0) as integer
   declare function copyPixels(srcImg as image_type) as integer
   declare function createFromBmp(fileName as string) as integer
   declare sub destroy()
   declare destructor()
end type

function image_type.create(sizeInit as xy_int, colorInit as ulong = 0) as integer
   pFbImg = imagecreate(sizeInit.x, sizeInit.y, colorInit)
   size = sizeInit
   return 0
end function

'Clean-up this stuff
function image_type.copyPixels(srcImg as image_type) as integer
   if size.x <> srcImg.size.x then return -1
   if size.y <> srcImg.size.y then return -2
   if pFbImg = 0 then return -3
   if srcImg.pFbImg = 0 then return -4
   dim as integer sizeSrc, sizeDst
   'dim as ulong ptr pPixelsSrc, pPixelsDst
   if imageinfo(srcImg.pFbImg, , , , , , sizeSrc) <> 0 then return -5
   if imageinfo(pFbImg, , , , , , sizeDst) <> 0 then return -6
   if sizeSrc <> sizeDst then return -7
   dim as integer i
   for i = 0 to (sizeSrc\4)-1
      cast(ulong ptr, pFbImg)[i] = cast(ulong ptr, srcImg.pFbImg)   [i]
   next
   'memcpy(dest as any ptr, src as any ptr, n as size_t)
   return 0
end function

function image_type.createFromBmp(fileName as string) as integer
   dim as bitmap_header bmp_header
   dim as xy_int bmpSize
   if fileExists(filename) then
      open fileName for binary as #1
         get #1, , bmp_header
      close #1
      bmpSize.x = bmp_header.biWidth
      bmpSize.y = bmp_header.biHeight
      create(bmpSize, &hff000000)
      bload fileName, pFbImg
      print "Bitmap loaded: " & filename
   else
      print "File not found: " & filename
      sleep 1000
      return -1
   end if
   return 0
end function

sub image_type.destroy()
   if (pFbImg <> 0) then
      imagedestroy(pFbImg)
      pFbImg = 0
   end if
end sub

destructor image_type()
   destroy()
end destructor

'===============================================================================

'Todo: control per r,g,b

type image_manip_type
   dim as single brightness = 0.0 '-1 ... +1
   dim as single contrast = 1.0 '+1 ... inf
   dim as single greyScale = 1.0 '0...+1...inf
   dim as single gamma = 1.0 '0...inf
   'dim as boolean simpleBlur = false
end type

type area_type
   dim as integer x1, y1
   dim as integer x2, y2
end type

function truncate(value as single) as ubyte
   dim as integer v = cint(value)
   if v < 0 then return 0
   if v > 255 then return 255
   return v
end function

function changeColors32(pFbImg as any ptr, area as area_type, im as image_manip_type) as integer
   dim as integer w, h, bypp, pitch
   dim as integer xi, yi
   dim as any ptr pPixels
   dim as rgba_union ptr pRow
   dim as single r, g, b, intensity
   if imageinfo(pFbImg, w, h, bypp, pitch, pPixels) <> 0 then return -1
   if bypp <> 4 then return -2 'only 32-bit images
   'Sanity checks:
   if pPixels = 0 then return -3
   if area.x1 < 0 or area.x1 >= w then return -4
   if area.y1 < 0 or area.y1 >= h then return -5
   if area.x2 < 0 or area.x2 >= w then return -6
   if area.y2 < 0 or area.y2 >= h then return -7

   for yi = area.y1 to area.y2
      pRow = pPixels + yi * pitch
      for xi = area.x1 to area.x2
         'convert to 0...+1 range
         r = pRow[xi].r / 255
         g = pRow[xi].g / 255
         b = pRow[xi].b / 255
         r = ((r + im.brightness) - 0.5) * im.contrast + 0.5
         g = ((g + im.brightness) - 0.5) * im.contrast + 0.5
         b = ((b + im.brightness) - 0.5) * im.contrast + 0.5
         intensity = 0.3 * r + 0.5 * g + 0.2 * b
         r = (r * im.greyScale + intensity * (1 - im.greyScale)) ^ im.gamma
         g = (g * im.greyScale + intensity * (1 - im.greyScale)) ^ im.gamma
         b = (b * im.greyScale + intensity * (1 - im.greyScale)) ^ im.gamma
         'convert back to 0...255
         pRow[xi].r = truncate(r * 255)
         pRow[xi].g = truncate(g * 255)
         pRow[xi].b = truncate(b * 255)
      next
   next
   return 0
end function

'===============================================================================

dim as image_type img1, img2
dim as image_manip_type imageManip
dim as integer result
dim as integer key
dim as string selection = "brightness"

screenres 800, 800, 32
width 800\8, 800\16

if img1.createFromBmp("Basil-cathedral-morning_800.bmp") <> 0 then end
img2.create(img1.size)

imageManip.brightness = 0.0 'default = 0.0
imageManip.contrast = 1.0 'default = 1.0
imageManip.greyScale = 1.0 'default = 1.0
imageManip.gamma = 1.0 'default = 1.0

while 1
   img2.copyPixels(img1)
   result = changeColors32(img2.pFbImg, type(200, 100, (img2.size.x-1)-200, (img2.size.y-1)-100), imageManip)
   put (0, 0), img2.pFbImg, pset
   locate 2, 2: print "result: "; result
   locate 4, 2: print "selection: "; selection
   locate 6, 2: print "key <1> brightness: "; imageManip.brightness
   locate 7, 2: print "key <2> contrast: "; imageManip.contrast
   locate 8, 2: print "key <3> greyScale: "; imageManip.greyScale
   locate 9, 2: print "key <4> gamma: "; imageManip.gamma
   locate 11, 2: print "key <up/down> to change"
   
   key = getkey()
   select case key
   case &h31 : selection = "brightness"
   case &h32 : selection = "contrast"
   case &h33 : selection = "greyScale"
   case &h34 : selection = "gamma"
   case &h48ff
      select case selection
      case "brightness" : imageManip.brightness += 0.1
      case "contrast" : imageManip.contrast *= 1.1
      case "greyScale" : imageManip.greyScale *= 1.1
      case "gamma" : imageManip.gamma *= 1.1
      end select
   case &h50ff
      select case selection
      case "brightness" : imageManip.brightness -= 0.1
      case "contrast" : imageManip.contrast /= 1.1
      case "greyScale" : imageManip.greyScale /= 1.1
      case "gamma" : imageManip.gamma /= 1.1
      end select
   case &h1b
      exit while
   end select
wend
lizard
Posts: 410
Joined: Oct 17, 2017 11:35
Location: Germany

Re: Image color manupilation

Postby lizard » Jun 09, 2018 12:51

Works fine here!

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 2 guests