UCL WIKI

UCL Logo
Child pages
  • Working with graphics: PPM format (Arrays, I/O, functions)
Skip to end of metadata
Go to start of metadata

The following program reads PPM image into array, transform it into grayscale and writes it into another PPM file. As an example, use test_picture.ppm

In order to convert a JPEG-file into PPM use

jpeg2ktopam filename.jpg

 

Exercise 1:Copy and paste into a Code:Blocks project, compile and "debug", i.e. walk through all steps to understand its functionality. 


Exercise 2: Write a subroutines to invert (x<->y) and reflect (x->Nx-x, y->Ny-y) the image
Exercise 3: Replace the call of subroutine gray_ppm in the main program with hue_rotation_ppm for a hue rotation using the following rotation matrix
 [ (1-cos(a))/3 + cos(a) (1-cos(a))/3 - sqrt(1/3) * sin(a) (1-cos(a))/3 + sqrt(1/3) * sin(a) ]
 [ (1-cos(a))/3 + sqrt(1/3) * sin(a) (1-cos(a))/3 + cos(a) (1-cos(a))/3 - sqrt(1/3) * sin(a) ]
 [ (1-cos(a))/3 - sqrt(1/3) * sin(a) (1-cos(a))/3 + sqrt(1/3) * sin(a) (1-cos(a))/3 + cos(a) ],
 where "a" is a rotation angle. Make sure you understand the mathematical operation behind. 

Exercise 4 (optional): Write and test a subroutine for 2D rotation of an image by an angle "alpha". Use the following rotation matrix

 

LaTeX Markup problem

Show/Hide latex markup

Show/Hide latex error

 

 

program work_ppm
  implicit none
  ! INTERFACE BLOCK
  ! when you are using external function or subroutine
  ! with the assumed-shape or allocatable arrays passed as arguments
  ! (some other types as well) it is required to specify the interface
  ! block for such function involving declaration of its arguments and their types
  ! and the type of the function value
  interface
    !subroutine read_ppm(fname, rgb_mat)
    !  character(*) :: fname
    !  integer, allocatable :: rgb_mat(:,:,:)
    !end subroutine read_ppm
    !subroutine write_ppm(fname, rgb_mat)
    !  character(*) :: fname
    !  integer rgb_mat(:,:,:)
    !end subroutine write_ppm
    !subroutine gray_ppm(rgb_mat)
    !  integer rgb_mat(:,:,:)
    !end subroutine gray_ppm
    !subroutine hue_rotation_ppm(deg, rgb_mat)
    !  real deg
    !  integer rgb_mat(:,:,:)
    !end subroutine hue_rotation_ppm
    !subroutine rotate_ppm(deg, rgb_mat)
    !  real deg
    !  integer, allocatable :: rgb_mat(:,:,:)
    !end subroutine rotate_ppm
    !subroutine antialiasing_ppm(rgb_mat)
    !  integer :: rgb_mat(:,:,:)
    !end subroutine antialiasing_ppm
    !subroutine filter_ppm(filter, rgb_mat, factor, bias)
    !  real :: filter(:,:)
    !  integer, allocatable :: rgb_mat(:,:,:)
    !  real, optional :: factor, bias
    !end subroutine filter_ppm
  end interface
  ! array for RGB map of PPM image
  integer, allocatable :: rgb_mat(:,:,:)  ! rgb(i,ix,iy), i=1..3 (red, green, or blue), ix, iy - pixel coordinates
  integer i
  real filter(5,5), factor, bias
  ! read PPM file
  call read_ppm('test_picture.ppm', rgb_mat)
  call gray_ppm(rgb_mat)
  ! create PPM file
  call write_ppm('test_picture_res.ppm', rgb_mat)
end program work_ppm


subroutine read_ppm(filename, rgb_mat)
  ! Reads PPM file into RGB matrix
  implicit none
  character(*), intent(in) :: filename
  integer, allocatable, intent(out) :: rgb_mat(:,:,:)
  integer iounit, hxres, hyres, ix, iy, info, npic, ncol
  character(len=80) buf
  character ccode
  print('(/a,1x,a)'), 'read PPM file:', trim(filename)
  iounit = 10
  open(unit=iounit, file=trim(filename), status='old', action='read')
  read(iounit,'(a2)') buf(1:2)
  read(iounit,'(a1)') buf(1:1)
  if (buf(1:1)/='#') backspace(iounit)
  read(iounit,*) hxres, hyres
  read(iounit,*) ncol
  print('(1x,a,1x,i,1x,i)'), 'resolution =', hxres, hyres
  if (allocated(rgb_mat)) deallocate(rgb_mat)
  allocate(rgb_mat(3,hxres,hyres), stat=info)
  if (info/=0) stop 'read_ppm error: failed to allocate rgb_mat'
  do iy=1, hyres
    do ix=1, hxres
      read(iounit,'(a1)',advance='no',iostat=info) ccode
      rgb_mat(1,ix,iy) = iachar(ccode)
      read(iounit,'(a1)',advance='no',iostat=info) ccode
      rgb_mat(2,ix,iy) = iachar(ccode)
      read(iounit,'(a1)',advance='no',iostat=info) ccode
      rgb_mat(3,ix,iy) = iachar(ccode)
    enddo
  enddo
  close(iounit)
  print('(a/)'), 'done'
end subroutine read_ppm

subroutine write_ppm(filename, rgb_mat)
  ! Creates PPM file from RGB matrix
  implicit none
  character(len=*), intent(in) :: filename
  integer, intent(in) :: rgb_mat(:,:,:)
  integer iounit, hxres, hyres, ix, iy, info, npic
  character(len=80)  buf
  iounit = 10
  hxres = size(rgb_mat,dim=2)
  hyres = size(rgb_mat,dim=3)
  print('(/a,1x,a)'), 'write PPM file:', trim(filename)
  print('(1x,a,1x,i,1x,i)'), 'resolution:', hxres, hyres
  open(unit=iounit, file=trim(filename), status='unknown', action='write',recl=3*hxres*hyres+10)
  write(iounit,'(a)') 'P6'
  write(iounit,*) hxres, hyres
  write(iounit,'(a)') '255'
  npic = 3*hxres*hyres
  do iy=1,hyres
    do ix=1,hxres
      write(iounit,'(3a)',advance='no') char(rgb_mat(1,ix,iy)), char(rgb_mat(2,ix,iy)), char(rgb_mat(3,ix,iy))
    enddo
  enddo
  close(iounit)
  print('(a/)'), 'done'
end subroutine write_ppm
 
subroutine gray_ppm(rgb_mat)
  ! Grayscale conversion of RGB matrix
  implicit none
  integer, intent(inout) :: rgb_mat(:,:,:)
  integer hxres, hyres, ix, iy
  real :: coefs(3)
  coefs = (/ 1.0/3.0, 1.0/3.0, 1.0/3.0 /)
  hxres = size(rgb_mat,dim=2)
  hyres = size(rgb_mat,dim=3)
  do iy=1, hyres
    do ix=1, hxres
      rgb_mat(1:3,ix,iy) = int( sum( rgb_mat(1:3,ix,iy) * coefs(1:3) ) )
    enddo
  enddo
end subroutine gray_ppm


subroutine hue_rotation_ppm(deg, rgb_mat)
  ! Hue rotation of RGB matrix by ab angle = "deg" degrees
  implicit none
  real, intent(in) :: deg
  integer, intent(inout) :: rgb_mat(:,:,:)
  integer hxres, hyres, ix, iy
  real cosa, sina, pi, mat(3,3)
  print('(/a,1x,f10.3,1x,a)'), 'rgb hue rotation, angle =', deg, 'deg'
  pi = acos(-1.0)
  ! define hue rotation matrix
  cosa = cos( deg*pi/180.0 )
  sina = sin( deg*pi/180.0 )
  mat(1,1) = cosa + (1.0 - cosa) / 3.0
  mat(1,2) = 1.0/3.0 * (1.0 - cosa) - sqrt(1.0/3.0) * sina
  mat(1,3) = 1.0/3.0 * (1.0 - cosa) + sqrt(1.0/3.0) * sina
  mat(2,1) = 1.0/3.0 * (1.0 - cosa) + sqrt(1.0/3.0) * sina
  mat(2,2) = cosa + 1.0/3.0*(1.0 - cosa)
  mat(2,3) = 1.0/3.0 * (1.0 - cosa) - sqrt(1.0/3.0) * sina
  mat(3,1) = 1.0/3.0 * (1.0 - cosa) - sqrt(1.0/3.0) * sina
  mat(3,2) = 1.0/3.0 * (1.0 - cosa) + sqrt(1.0/3.0) * sina
  mat(3,3) = cosa + 1.0/3.0 * (1.0 - cosa)
  print('(/1x,a)'), 'hue rotation matrix:'
  print('(3(3(1x,f10.6)/))'), ((mat(iy,ix), ix=1, 3), iy=1, 3)
  ! rotate RGB map
  hxres = size(rgb_mat,dim=2)
  hyres = size(rgb_mat,dim=3)
  do iy=1, hyres
    rgb_mat(1:3,1:hxres,iy) = int( matmul(mat(1:3,1:3), rgb_mat(1:3,1:hxres,iy) ) )
  enddo
  print('(a/)'), 'done'
end subroutine hue_rotation_ppm


subroutine antialiasing_ppm(rgb_mat)
  implicit none
  integer, intent(inout) :: rgb_mat(:,:,:)
  integer hxres, hyres, ix, iy
  hxres = size(rgb_mat,dim=2)
  hyres = size(rgb_mat,dim=3)
  do iy=2, hyres-1
    do ix=2, hxres-1
      if (all(rgb_mat(1:3,ix,iy)==0)) then
        rgb_mat(1:3,ix,iy) = nint( real(rgb_mat(1:3,ix-1,iy) + rgb_mat(1:3,ix+1,iy) + rgb_mat(1:3,ix,iy-1) + rgb_mat(1:3,ix,iy+1))/4.0 )
      endif
    enddo
  enddo
end subroutine antialiasing_ppm
subroutine filter_ppm(filter, rgb_mat, factor_, bias_)
  implicit none
  real, intent(in) :: filter(:,:)
  integer, allocatable, intent(inout) :: rgb_mat(:,:,:)
  real, optional, intent(in) :: factor_, bias_
  integer hxres, hyres, fxres, fyres, ix, iy, ifx, ify, imx, imy, info
  integer, allocatable :: rgb_mat_(:,:,:)
  real rgb(3), factor, bias
  factor = 1.0
  bias = 0.0
  if (present(factor_)) factor = factor_
  if (present(bias_)) bias = bias_
  hxres = size(rgb_mat,dim=2)
  hyres = size(rgb_mat,dim=3)
  fxres = size(filter,dim=1)
  fyres = size(filter,dim=2)
  allocate(rgb_mat_(3,hxres,hyres), stat=info)
  if (info/=0) stop 'filter_ppm error: failed to allocate rgb_mat_'
  do iy=1, hyres
    do ix=1, hxres
      rgb = 0
      do ify=1, fyres
        do ifx=1, fxres
          imx = mod( ix - nint(real(fxres)/2.0) + ifx + hxres, hxres)
          imy = mod( iy - nint(real(fyres)/2.0) + ify + hyres, hyres)
          rgb = rgb + rgb_mat(1:3,imx,imy) * filter(ifx,ify)
        enddo
      enddo
      rgb_mat_(1,ix,iy) = min(max(int(rgb(1)*factor+bias), 0), 255)
      rgb_mat_(2,ix,iy) = min(max(int(rgb(2)*factor+bias), 0), 255)
      rgb_mat_(3,ix,iy) = min(max(int(rgb(3)*factor+bias), 0), 255)
    enddo
  enddo
  deallocate(rgb_mat)
  call move_alloc(rgb_mat_, rgb_mat)
end subroutine filter_ppm

  • No labels