[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 pacakge. So, instead: * The first algorithm simply flattens the filter and the part of the image being treated, multiplies the elements one by one and determines the sum. This algorithm loops over parts of the image. * The second algorithm shifts the image, scales it according to the filter's entries and sums these weighted images. 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] ====== <>Category Mathematics | Category Image Processing