Arjen Markus (23 July 2009) Exploring the possibilities of the Tensor package, I thought it would be fun and useful to see how you can use it to filter images. after all: an image can be regarded as a two-dimensional array of numerical data and the Tensor package is meant to deal with such data.
The case I had in mind was simple edge detection. Basically: determine the gradients in intensity in the image and use a "clipping" function to highlight the strong gradients.
It took me some experimentation to find out that matrix multiplication (tensor multiplication if you like) will not do the job - it is a limitation of the matrix multiplication itself, not of the Tensor package. So, instead:
Here is the output:
Original: -------------------- ********* ********* ********* ********* ********* ********* -------------------- Filtered: -------------------- ********* * * * * * * * * * * ********** -------------------- {1 18} {1 18} {1 18} {2 19} {2 19} {1 18} Filtered (alternative): -------------------- ********* * * * * * * * * * * ********** --------------------
The code:
# filter.tcl -- # Illustrate the use of the Tensor package to do filtering # on images # # Note: # The filtering procedures assume the filter dimensions are odd! # package require Tensor namespace eval filter { variable count 0 } # filteredImage -- # Create a filtered image # proc filter::filteredImage {filter image} { variable count incr count ::tensor::create img$count -type double -size [$image dimensions] ::tensor::create part -type double -size [$filter dimensions] set size [expr [join [$filter dimensions] *]] set fdims [$filter dimensions] ::tensor::create rfilter -type double -size $fdims ::tensor::create rpart -type double -size $size ::tensor::create cell -type double -size 1 foreach {rows cols} [$image dimensions] {break} foreach {frows fcols} [$filter dimensions] {break} set rowsf [expr {$frows/2}] set colsf [expr {$fcols/2}] set rowsl [expr {$rows-$frows/2}] set colsl [expr {$cols-$fcols/2}] rfilter = tensor filter rfilter reshape $size for {set i $rowsf} {$i < $rowsl} {incr i} { for {set j $colsf} {$j < $colsl} {incr j} { part = tensor $image section \ [list [list [expr {$i-$frows/2}] [expr {$i+$frows/2}]] \ [list [expr {$j-$fcols/2}] [expr {$j+$fcols/2}]] ] part reshape $size rpart = tensor part rpart *= tensor rfilter part reshape $fdims cell = contraction rpart 0 img$count section [list $i $j] = scalar [cell] } } rename part {} rename rpart {} rename rfilter {} rename cell {} return img$count } # filteredImageX -- # Create a filtered image - alternative implementation # proc filter::filteredImageX {filter image} { variable count incr count ::tensor::create img$count -type double -size [$image dimensions] ::tensor::create partial -type double -size [$image dimensions] foreach {rows cols} [$image dimensions] {break} foreach {frows fcols} [$filter dimensions] {break} set psection [list [list [expr {$frows/2}] [expr {$rows-$frows/2-1}]] \ [list [expr {$fcols/2}] [expr {$cols-$fcols/2-1}]] ] for {set i 0} {$i < $frows} {incr i} { for {set j 0} {$j < $fcols} {incr j} { set factor [$filter section [list $i $j]] if { $factor != 0.0 } { set isection [list [list $i [expr {$rows+$i-$frows}]] \ [list $j [expr {$cols+$j-$fcols}]] ] puts $isection partial section $psection = tensor $image section $isection partial *= scalar $factor img$count += tensor partial } } } rename partial {} return img$count } # main -- # Test it # ::tensor::create filter -initial {{0.0 0.0 0.0} {0.0 -2.0 1.0} {0.0 1.0 0.0}} ::tensor::create image -size {20 20} image section {{5 10} {7 15}} = scalar 1.0 puts "Original:" puts [string repeat - 20] foreach row [image] { foreach col $row { puts -nonewline [expr {abs($col) > 0.5? "*": " "}] } puts "" } puts [string repeat - 20] set result [filter::filteredImage filter image] puts "Filtered:" # # Numerical output: # puts [join [$result] \n] puts [string repeat - 20] foreach row [$result] { foreach col $row { puts -nonewline [expr {abs($col) > 0.5? "*": " "}] } puts "" } puts [string repeat - 20] # # Use alternative implementation # set result [filter::filteredImageX filter image] puts "Filtered (alternative):" # # Numerical output: # puts [join [$result] \n] puts [string repeat - 20] foreach row [$result] { foreach col $row { puts -nonewline [expr {abs($col) > 0.5? "*": " "}] } puts "" } puts [string repeat - 20]