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]