AKTIVE

kernels.tcl at trunk
Login

kernels.tcl at trunk

File etc/generator/virtual/pattern/kernels.tcl artifact 4a69924ae9 on branch trunk


     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
   100
   101
   102
   103
   104
   105
   106
   107
   108
   109
   110
   111
   112
   113
   114
   115
   116
   117
   118
   119
   120
   121
   122
   123
   124
   125
   126
   127
   128
   129
   130
   131
   132
   133
   134
   135
   136
   137
   138
   139
   140
   141
   142
   143
   144
   145
   146
   147
   148
   149
   150
   151
   152
   153
   154
   155
   156
   157
   158
   159
   160
   161
   162
   163
   164
   165
   166
   167
   168
   169
   170
   171
   172
   173
   174
   175
   176
   177
   178
   179
   180
   181
   182
   183
   184
   185
   186
   187
   188
   189
   190
   191
   192
   193
   194
   195
   196
   197
   198
   199
   200
   201
   202
   203
   204
   205
   206
## -*- mode: tcl ; fill-column: 90 -*-
# # ## ### ##### ######## ############# #####################
## Generators -- Virtual Image - convolution kernels
#
## - gauss (3/5/7/9; x, y, xy; discrete)
## - emboss
## - kirsch  (x, y, md, sd)
## - laplace (4, 8, X)
## - prewitt (x, y, md, sd)
## - roberts (x, y)
## - scharr  (x, y)
## - sobel   (x, y, md, sd)
## - sharp   (4, 8, X)

# # ## ### ##### ######## ############# #####################
## md = main diagonal
## sd = secondary diagonal

operator {w h description factor kernel} {
    image::kernel::gauss3::x   3 1 {@ian blur effect}        1/4.   { 1 2 1 }
    image::kernel::gauss3::y   1 3 {@ian blur effect}        1/4.   { 1 2 1 }
    image::kernel::gauss3::xy  3 3 {@ian blur effect}        1/16.  { 1 2 1  2 4 2  1 2 1 }
    image::kernel::gauss5::x   5 1 {@ian blur effect}        1/16.  { 1 4 6 4 1 }
    image::kernel::gauss5::y   1 5 {@ian blur effect}        1/16.  { 1 4 6 4 1 }
    image::kernel::gauss7::x   7 1 {@ian blur effect}        1/64.  { 1 6 15 20 15 6 1 }
    image::kernel::gauss7::y   1 7 {@ian blur effect}        1/64.  { 1 6 15 20 15 6 1 }
    image::kernel::gauss9::x   9 1 {@ian blur effect}        1/128. { 1 8 28 56 70 56 28 8 1 }
    image::kernel::gauss9::y   1 9 {@ian blur effect}        1/128. { 1 8 28 56 70 56 28 8 1 }

    image::kernel::kirsch::md  3 3 {@ edge detection}         {}    { -3   5  5   -3 0  5  -3 -3 -3 }
    image::kernel::kirsch::sd  3 3 {@ edge detection}         {}    {  5   5 -3    5 0 -3  -3 -3 -3 }
    image::kernel::kirsch::x   3 3 {@ edge detection}         {}    {  5  -3 -3    5 0 -3   5 -3 -3 }
    image::kernel::kirsch::y   3 3 {@ edge detection}         {}    {  5   5  5   -3 0 -3  -3 -3 -3 }

    image::kernel::prewitt::md 3 3 {@ edge detection}         {}    {  0   1  1   -1 0  1  -1 -1  0 }
    image::kernel::prewitt::sd 3 3 {@ edge detection}         {}    { -1  -1  0   -1 0  1   0  1  1 }
    image::kernel::prewitt::x  3 3 {@ edge detection}         {}    { -1   0  1   -1 0  1  -1  0  1 }
    image::kernel::prewitt::y  3 3 {@ edge detection}         {}    { -1  -1 -1    0 0  0   1  1  1 }

    image::kernel::roberts::x  3 3 {@ cross edge detection}   {}    {  0  -1  0    1 0  0   0  0  0 }
    image::kernel::roberts::y  3 3 {@ cross edge detection}   {}    { -1   0  0    0 1  0   0  0  0 }

    image::kernel::scharr::x   3 3 {@ edge detection}         {}    { -3   0  3  -10 0 10  -3  0  3 }
    image::kernel::scharr::y   3 3 {@ edge detection}         {}    { -3 -10 -3    0 0  0   3 10  3 }

    image::kernel::sobel::md   3 3 {@ edge detection}         {}    {  0  -1 -1    2 0 -2   1  1  0 }
    image::kernel::sobel::sd   3 3 {@ edge detection}         {}    {  1   1  0    2 0 -2   0 -1 -1 }
    image::kernel::sobel::x    3 3 {@ edge detection}         {}    {  1   0 -1    2 0 -2   1  0 -1 }
    image::kernel::sobel::y    3 3 {@ edge detection}         {}    {  1   2  1    0 0  0  -1 -2 -1 }

    image::kernel::emboss      3 3 {embossing effect}         {}    {  2   0  0    0 -1  0  0  0 -1 }

    image::kernel::laplace::4  3 3 {laplacian edge detection} {}    {  0  -1  0   -1  4 -1  0 -1  0 }
    image::kernel::laplace::8  3 3 {laplacian edge detection} {}    { -1  -1 -1   -1  8 -1 -1 -1 -1 }
    image::kernel::laplace::X  3 3 {laplacian edge detection} {}    {  1  -2  1   -2  4 -2  1 -2  1 }

    image::kernel::sharp::4    3 3 {sharpening effect}        {}    {  0  -1  0   -1  5 -1  0 -1  0 }
    image::kernel::sharp::8    3 3 {sharpening effect}        {}    { -1  -1 -1   -1  9 -1 -1 -1 -1 }
    image::kernel::sharp::X    3 3 {sharpening effect}        {}    {  1  -2  1   -2  5 -2  1 -2  1 }
} {
    op -> _ _ ref _
    set description [string map [list @ $ref] $description]

    switch -exact -- $ref {
	prewitt { ref https://en.wikipedia.org/wiki/Prewitt_operator }
	sobel   { ref https://en.wikipedia.org/wiki/Sobel_operator   }
	scharr  { ref https://en.wikipedia.org/wiki/Scharr_operator  }
	roberts { ref https://en.wikipedia.org/wiki/Roberts_cross    }
    }
    switch -exact -- $ref {
	prewitt -
	sobel   -
	scharr  -
	roberts -
	laplace { ref http://www.holoborodko.com/pavel/image-processing/edge-detection }
    }
    ref https://wiki.tcl-lang.org/page/TkPhotoLab

    if {$factor ne {}} {
	set factor [expr $factor]
	def scale "factor $factor"
    } else {
	def scale {}
    }

    section generator virtual

    if {![string match "gauss*" $ref]} {
	example { | -int -matrix }
    } else {
	example { | -matrix }
    }

    note Returns convolution kernel for $description

    body {
        aktive image from matrix width @@w@@ height @@h@@ @@scale@@ values @@kernel@@
    }
}

# # ## ### ##### ######## ############# #####################

operator image::kernel::gauss::discrete {
    section generator virtual

    ref http://en.wikipedia.org/wiki/Scale_space_implementation#The_discrete_Gaussian_kernel
    # G(x,sigma) = exp(-t)*I_x(t), where t = sigma^2
    # and I_x = Modified Bessel function of Order x

    example {sigma 1          | -matrix }
    example {sigma 2          | -matrix }
    example {sigma 1 radius 6 | -matrix }

    double                                        sigma  Kernel spread, as standard deviation to cover.
    uint?   {[expr {max(1,int(ceil(3*$sigma)))}]} radius Kernel radius, defaults to max(1,ceil(3*sigma)).

    note Returns the 1D discrete gaussian convolution kernel, for the specified sigma and radius. \
	By default sigma is 1. \
	By default the radius is max(1,ceil(3*sigma)).

    body {
	package require math::special
	if {$sigma <= 0} { aktive error "Invalid sigma $sigma, expected a value > 0" }

	# Compute the upper half of the kernel (0...radius).
	set table {}
	set t [expr {$sigma ** 2}]

	for {set x 0} {$x <= $radius} {incr x} {
	    set v [expr {exp(-$t)*[math::special::I_n $x $t]}]
	    lappend table $v
	}

	# Compute lower half of the table as reflection of the upper half, and join the pieces.

	if {[llength $table] > 1} {
	    set table [linsert $table 0 {*}[lreverse [lrange $table 1 end]]]
	}

	# ATTENTION ______________________________________________________________
	##
	# Should we do the "correction" below ?
	# Or should we keep the difference to 1 as inevitable error due to truncating the infinite kernel ?
	##
	# ______________________________________________________________ ATTENTION

	# Compute scale factor normalizing the sum to 1.
	set scale [expr { 1. / [tcl::mathop::+ {*}$table] }]
	## puts XXXSCA|[tcl::mathop::+ {*}$table]|

	# Apply scale factor outside of `from matrix` -- easier to test, can expect a
	# fixed factor 1.
	set table [lmap x $table { expr {$x*$scale} }]

	# Compute anti-scale factor - verify that this is now 1
	## puts XXXSCB|[tcl::mathop::+ {*}$table]|

	# At last construct and return the kernel
	aktive image from matrix width [llength $table] height 1 values {*}$table
    }
}


# # ## ### ##### ######## ############# #####################

operator image::kernel::lanczos {
    section generator virtual

    example {                  | -matrix }
    example {order 2           | -matrix }
    example {order 2 step 0.25 | -matrix }

    ref https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel

    uint?   3 order Order of the lanczos kernel. Acceptable minimum is 2.
    double? 1 step  X-delta between kernel elements.

    note Returns lanczos convolution kernel of the specified order. \
	The default order is 3. Step expands the kernel to the given \
	resolution (default 1).

    body {
	if {$order < 2} { aktive error "Invalid order $order, expected a value >= 2" }

	# Compute the upper half of the kernel (0...order)

	set steps [expr {ceil(double($order)/double($step))}]
	set table {}
	for {set n 0} {$n < $steps} {incr n} {
	    set v [expr {lanczos($order, $n*$step)}]
	    lappend table $v
	}

	# Compute lower half of the table as reflection of the upper half, and join the pieces.
	if {[llength $table] > 1} {
	    set table [linsert $table 0 {*}[lreverse [lrange $table 1 end]]]
	}

	# At last construct and return the kernel
	aktive image from matrix width [llength $table] height 1 values {*}$table
    }
}

##
# # ## ### ##### ######## ############# #####################
::return