# UCL WIKI

##### Child pages
• Working with graphics: PPM format (Arrays, I/O, functions)
Go to start of banner

# Working with graphics: PPM format (Arrays, I/O, functions)

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 \documentclass{article} \usepackage{amsmath} \usepackage{amsthm} \usepackage{amssymb} \usepackage{bm} \newcommand{\mx}[1]{\mathbf{\bm{#1}}} % Matrix command \newcommand{\vc}[1]{\mathbf{\bm{#1}}} % Vector command \newcommand{\T}{\text{T}} % Transpose \pagestyle{empty} \begin{document}$$\left( \begin{array}{cc} \cos\alpha & -\sin\alpha \\ \sin\alpha & \cos\alpha \end{array} \right)$$\end{document} Show/Hide latex error Unable to find DVI conversion log file.

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
!  character(*) :: fname
!  integer, allocatable :: rgb_mat(:,:,:)
!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
call gray_ppm(rgb_mat)
! create PPM file
call write_ppm('test_picture_res.ppm', rgb_mat)
end program work_ppm

! 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
iounit = 10
if (buf(1:1)/='#') backspace(iounit)
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
rgb_mat(1,ix,iy) = iachar(ccode)
rgb_mat(2,ix,iy) = iachar(ccode)
rgb_mat(3,ix,iy) = iachar(ccode)
enddo
enddo
close(iounit)
print('(a/)'), 'done'

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
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