From 38c65305f497b33273b9b0083c4d124dbacc435f Mon Sep 17 00:00:00 2001 From: yang162132 Date: Fri, 28 Oct 2022 09:59:52 +0800 Subject: [PATCH 1/2] add some kinds of kernel --- .../raster/mapalgebra/focal/Kernel.scala | 574 +++++++++++++++++- .../raster/mapalgebra/focal/KernelSpec.scala | 333 ++++++++++ 2 files changed, 877 insertions(+), 30 deletions(-) create mode 100644 raster/src/test/scala/geotrellis/raster/mapalgebra/focal/KernelSpec.scala diff --git a/raster/src/main/scala/geotrellis/raster/mapalgebra/focal/Kernel.scala b/raster/src/main/scala/geotrellis/raster/mapalgebra/focal/Kernel.scala index 184f1a11ed..77fd94093f 100644 --- a/raster/src/main/scala/geotrellis/raster/mapalgebra/focal/Kernel.scala +++ b/raster/src/main/scala/geotrellis/raster/mapalgebra/focal/Kernel.scala @@ -19,10 +19,10 @@ package geotrellis.raster.mapalgebra.focal import geotrellis.raster._ /** - * [[Kernel]] - * - * Represents a neighborhood that is represented by a tile. - */ + * [[Kernel]] + * + * Represents a neighborhood that is represented by a tile. + */ case class Kernel(tile: Tile) extends Neighborhood { require(tile.rows == tile.cols, "Kernel tile must be square") require(tile.rows % 2 == 1, "Kernel tile must have odd dimension") @@ -32,6 +32,58 @@ case class Kernel(tile: Tile) extends Neighborhood { val hasMask = false def cellType = tile.cellType + + def add(otherkernel: Kernel): Kernel = { + val selfarr = tile.toArrayDouble() + val otherarr = otherkernel.tile.toArrayDouble() + val otherextent = otherkernel.extent + + if (extent == otherextent) { + Kernel(DoubleArrayTile(selfarr.zip(otherarr).map { case (x, y) => x + y }, tile.rows, tile.rows)) + } else if (extent < otherextent) { + val diff = otherextent - extent + val newarr = otherarr + var r = 0 + while (r < tile.rows) { + var c = 0 + while (c < tile.rows) { + newarr((diff + r) * otherkernel.tile.rows + diff + c) = newarr((diff + r) * otherkernel.tile.rows + diff + c) + selfarr(r * tile.rows + c) + c += 1 + } + r += 1 + } + Kernel(DoubleArrayTile(newarr, otherkernel.tile.rows, otherkernel.tile.rows)) + } else { + val diff = extent - otherextent + val newarr = selfarr + var r = 0 + while (r < otherkernel.tile.rows) { + var c = 0 + while (c < otherkernel.tile.rows) { + newarr((diff + r) * tile.rows + diff + c) = newarr((diff + r) * tile.rows + diff + c) + otherarr(r * otherkernel.tile.rows + c) + c += 1 + } + r += 1 + } + Kernel(DoubleArrayTile(newarr, tile.rows, tile.rows)) + } + } + + /** + * + * Returns a kernel which has each of its weights multiplicatively inverted. + * Weights with a value of zero are not inverted and remain zero. + * + */ + def inverse(): Kernel = { + val newarr = tile.toArrayDouble().map(value => { + if (value != 0) + 1.0 / value + else + 0 + }) + Kernel(DoubleArrayTile(newarr, tile.rows, tile.rows)) + } } object Kernel { @@ -42,7 +94,7 @@ object Kernel { val w = 2 * nbhd.extent + 1 val size = w * w - val tile = IntArrayTile(new Array[Int](size), w, w) + val tile = DoubleArrayTile(new Array[Double](size), w, w) var r = 0 while (r < w) { @@ -57,19 +109,20 @@ object Kernel { new Kernel(tile) } + /** - * Creates a Gaussian kernel. Can be used with the [[Convolve]] or - * KernelDensity operations. - * - * @param size Number of rows of the resulting tile. - * @param sigma Sigma parameter for Gaussian - * @param amp Amplitude for Gaussian. Will be the value at the center of - * the resulting tile. - * - * @note Tile will be IntConstantNoDataCellType - */ + * Creates a Gaussian kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param size Number of rows of the resulting tile. + * @param sigma Sigma parameter for Gaussian + * @param amp Amplitude for Gaussian. Will be the value at the center of + * the resulting tile. + * + * @note Tile will be IntConstantNoDataCellType + */ def gaussian(size: Int, sigma: Double, amp: Double): Kernel = { - val output = IntArrayTile.empty(size, size) + val output = DoubleArrayTile.empty(size, size) val denom = 2.0*sigma*sigma @@ -79,8 +132,8 @@ object Kernel { c = 0 while(c < size) { val rsqr = (c - (size / 2)) * (c - (size / 2)) + (r - (size / 2)) * (r - (size / 2)) - val g = (amp * (math.exp(-rsqr / denom))).toInt - output.set(c, r, g) + val g = amp * (math.exp(-rsqr / denom)) + output.setDouble(c, r, g) c += 1 } r += 1 @@ -90,17 +143,17 @@ object Kernel { } /** - * Creates a Circle kernel. Can be used with the [[Convolve]] or - * KernelDensity operations. - * - * @param size Number of rows in the resulting tile. - * @param cellWidth Cell width of the resutling tile. - * @param rad Radius of the circle. - * - * @note Tile will be IntConstantNoDataCellType - */ + * Creates a Circle kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param size Number of rows in the resulting tile. + * @param cellWidth Cell width of the resutling tile. + * @param rad Radius of the circle. + * + * @note Tile will be IntConstantNoDataCellType + */ def circle(size: Int, cellWidth: Double, rad: Int) = { - val output = IntArrayTile.empty(size, size) + val output = DoubleArrayTile.empty(size, size) val rad2 = rad*rad @@ -108,8 +161,8 @@ object Kernel { var r = -w var c = -w while(r <= w) { - while(c <= w) { - output.set(c+w, r+w, if (r * r + c * c <= rad2) 1 else 0) + while (c <= w) { + output.setDouble(c + w, r + w, if (r * r + c * c <= rad2) 1 else 0) c += 1 } c = -w @@ -118,4 +171,465 @@ object Kernel { Kernel(output) } + + + /** + * Creates a chebyshev kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param rad Radius of the kernel. + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def chebyshev(rad: Int, normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 2 * rad + 1 + var output: Array[Double] = Array.ofDim(size * size) + var r = 0 + var c = 0 + var sum: Double = 0 + while (r < size) { + c = 0 + while (c < size) { + val g = Math.max(Math.abs(rad - r), Math.abs(rad - c)) + output(c * size + r) = g + sum = sum + g + c += 1 + } + r += 1 + } + if (normalize == true) + output = output.map(_ / sum * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a Generates a 3x3 Prewitt's Compass edge-detection kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def compass(normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 3 + var output: Array[Double] = Array(1.0, 1.0, -1.0, 1.0, -2.0, -1.0, 1.0, 1.0, -1.0) + + if (normalize == true) + output = output.map(_ / 5.0 * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a Generates a cross-shaped('X') boolean kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param rad Radius of the kernel. + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def cross(rad: Int, normalize: Boolean = true, magnitude: Float = 1): Kernel = { + val size = 2 * rad + 1 + var output: Array[Double] = Array.ofDim(size * size) + var r = 0 + var c = 0 + var sum: Double = 4 * rad + 1 + while (r < size) { + c = 0 + while (c < size) { + var g = 0 + if (r == c || 2 * rad - r == c) { + g = 1 + } + output(c * size + r) = g + c += 1 + } + r += 1 + } + if (normalize == true) + output = output.map(_ / sum * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a diamond-shaped kernel ('◇'). Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param rad Radius of the kernel. + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def diamond(rad: Int, normalize: Boolean = true, magnitude: Float = 1): Kernel = { + val size = 2 * rad + 1 + var output: Array[Double] = Array.ofDim(size * size) + var r = 0 + var c = 0 + var sum: Double = 0 + while (r < size) { + c = 0 + while (c < size) { + if (Math.abs(rad - r) + Math.abs(rad - c) <= rad) { + output(c * size + r) = 1.0 + sum = sum + 1.0 + } else { + output(c * size + r) = 0 + } + c += 1 + } + r += 1 + } + if (normalize == true) + output = output.map(_ / sum * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a distance kernel based on Euclidean (straight-line) distance. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param rad Radius of the kernel. + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def euclidean(rad: Int, normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 2 * rad + 1 + var output: Array[Double] = Array.ofDim(size * size) + var r = 0 + var c = 0 + var sum: Double = 0 + while (r < size) { + c = 0 + while (c < size) { + val rc = r - rad; + val cc = c - rad; + val g = Math.sqrt(Math.pow(rad - c, 2) + Math.pow(rad - r, 2)) + output(c * size + r) = g + sum = sum + g + c += 1 + } + r += 1 + } + if (normalize == true) + output = output.map(_ / sum * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a Gaussian kernel (by Two-dimensional Gaussian distribution). Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param rad Radius of the kernel. + * @param sigma Standard deviation of the Gaussian function + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def gaussianWithoutAmp(rad: Int, sigma: Float, normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 2 * rad + 1 + var output: Array[Double] = Array.ofDim(size * size) + var r = 0 + var c = 0 + var sum: Double = 0 + while (r < size) { + c = 0 + while (c < size) { + val calc = -(Math.pow(rad - c, 2) + Math.pow(rad - r, 2)) + val param = 2 * sigma * sigma + val g = (1 / (Math.PI * param)) * Math.exp(calc / param) + output(c * size + r) = g + sum = sum + g + c += 1 + } + r += 1 + } + if (normalize == true) + output = output.map(_ / sum * magnitude) + else + output = output.map(_ * magnitude) + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a 3x3 Kirsch's Compass edge-detection kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param direction The direction of kernel use "N、NW、W、SW、S、SE、E and NE" + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def kirsch(direction: String = "W", normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 3 + var output: Array[Double] = direction match { + case "N" => Array(5.0, 5.0, 5.0, -3.0, 0, -3.0, -3.0, -3.0, -3.0) + case "NW" => Array(5.0, 5.0, -3.0, 5.0, 0, -3.0, -3.0, -3.0, -3.0) + case "W" => Array(5.0, -3.0, -3.0, 5.0, 0, -3.0, 5.0, -3.0, -3.0) + case "SW" => Array(-3.0, -3.0, -3.0, 5.0, 0, -3.0, 5.0, 5.0, -3.0) + case "S" => Array(-3.0, -3.0, -3.0, -3.0, 0, -3.0, 5.0, 5.0, 5.0) + case "SE" => Array(-3.0, -3.0, -3.0, -3.0, 0, 5.0, -3.0, 5.0, 5.0) + case "E" => Array(-3.0, -3.0, 5.0, -3.0, 0, 5.0, -3.0, -3.0, 5.0) + case "NE" => Array(-3.0, 5.0, 5.0, -3.0, 0, 5.0, -3.0, -3.0, -3.0) + } + + if (normalize == true) + output = output.map(_ / 15.0 * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a 3x3 Laplacian-4 edge-detection kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def laplacian4(normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 3 + var output: Array[Double] = Array(0, 1, 0, 1, -4, 1, 0, 1, 0) + + if (normalize == true) + output = output.map(_ / 4.0 * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a 3x3 Laplacian-8 edge-detection kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def laplacian8(normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 3 + var output: Array[Double] = Array(1, 1, 1, 1, -8, 1, 1, 1, 1) + + if (normalize == true) + output = output.map(_ / 8.0 * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a chebyshev kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param rad Radius of the kernel. + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def manhattan(rad: Int, normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 2 * rad + 1 + var output: Array[Double] = Array.ofDim(size * size) + var r = 0 + var c = 0 + var sum: Double = 0 + while (r < size) { + c = 0 + while (c < size) { + val g = Math.abs(rad - r) + Math.abs(rad - c) + output(c * size + r) = g + sum = sum + g + c += 1 + } + r += 1 + } + if (normalize == true) + output = output.map(_ / sum * magnitude) + else + output = output.map(_ * magnitude) + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Createsan octagon-shaped boolean kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param rad Radius of the kernel. + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def octagon(rad: Int, normalize: Boolean = true, magnitude: Float = 1): Kernel = { + val size = 2 * rad + 1 + var output: Array[Double] = Array.ofDim(size * size) + var r = 0 + var c = 0 + var sum: Double = 0 + while (r < size) { + c = 0 + while (c < size) { + if (Math.abs(rad - r) + Math.abs(rad - c) <= 1.5 * rad) { + output(c * size + r) = 1.0 + sum = sum + 1.0 + } else { + output(c * size + r) = 0 + } + c += 1 + } + r += 1 + } + if (normalize == true) + output = output.map(_ / sum * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a plus-shaped boolean kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param rad Radius of the kernel. + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def plus(rad: Int, normalize: Boolean = true, magnitude: Float = 1): Kernel = { + val size = 2 * rad + 1 + var output: Array[Double] = Array.ofDim(size * size) + var r = 0 + var c = 0 + var sum: Double = 4 * rad + 1 + while (r < size) { + c = 0 + while (c < size) { + var g = 0 + if (r == rad || c == rad) { + g = 1 + } + output(c * size + r) = g + c += 1 + } + r += 1 + } + if (normalize == true) + output = output.map(_ / sum * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a 3x3 Prewitt edge-detection kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def prewitt(normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 3 + var output: Array[Double] = Array(1, 0, -1, 1, 0, -1, 1, 0, -1) + + if (normalize == true) + output = output.map(_ / 3.0 * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a 2x2 Roberts edge-detection kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def roberts(magnitude: Float = 1): Kernel = { + val size = 2 + var output: Array[Double] = Array(1, 0, 0, -1) + output = output.map(_ * magnitude) + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a 3x3 Sobel edge-detection kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def Sobel(normalize: Boolean = false, magnitude: Float = 1): Kernel = { + val size = 3 + var output: Array[Double] = Array(-1, 0, 1, -2, 0, 2, 1, 0, 1) + + if (normalize == true) + output = output.map(_ / 4.0 * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + /** + * Creates a square-shaped boolean kernel. Can be used with the [[Convolve]] or + * KernelDensity operations. + * + * @param rad Radius of the kernel. + * @param normalize Normalize the kernel values to sum to 1. + * @param magnitude Scale each value by this amount. + * @note Tile will be DoubleConstantNoDataCellType + */ + def square(rad: Int, normalize: Boolean = true, magnitude: Float = 1): Kernel = { + val size = 2 * rad + 1 + var output: Array[Double] = Array.fill(size * size)(1.0) + val sum = size * size + if (normalize == true) + output = output.map(_ / sum * magnitude) + else + output = output.map(_ * magnitude) + + val arrTile = DoubleArrayTile(output, size, size) + Kernel(arrTile) + } + + } diff --git a/raster/src/test/scala/geotrellis/raster/mapalgebra/focal/KernelSpec.scala b/raster/src/test/scala/geotrellis/raster/mapalgebra/focal/KernelSpec.scala new file mode 100644 index 0000000000..f2e0cf00e2 --- /dev/null +++ b/raster/src/test/scala/geotrellis/raster/mapalgebra/focal/KernelSpec.scala @@ -0,0 +1,333 @@ +/* + * Copyright 2016 Azavea + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package geotrellis.raster.mapalgebra.focal + +import geotrellis.raster._ +import geotrellis.raster.io.geotiff.{GeoTiffReader, MultibandGeoTiff} +import geotrellis.raster.mapalgebra.focal.Kernel._ +import org.scalatest.funsuite.AnyFunSuite + +class KernelSpec extends AnyFunSuite { + test("chebyshev") { + val chebyshevKernel = chebyshev(3) + val tile = chebyshevKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("compass") { + val compassKernel = compass() + val tile = compassKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("cross") { + val crossKernel = cross(3, false, 100) + val tile = crossKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + test("diamond") { + val diamondKernel = diamond(3, false) + val tile = diamondKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("euclidean") { + val euclideanKernel = euclidean(3, false) + val tile = euclideanKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r).formatted("%.3f").toDouble + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("gaussianWithoutAmp") { + val gaussianKernel = gaussianWithoutAmp(3, 1) + val tile = gaussianKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("kirsch") { + val kirschKernel = kirsch("S") + val tile = kirschKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + test("laplacian4") { + val laplacian4Kernel = laplacian4(true) + val tile = laplacian4Kernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + + test("laplacian8") { + val laplacian8Kernel = laplacian8(true) + val tile = laplacian8Kernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("manhattan") { + val manhattanKernel = manhattan(3, true) + val tile = manhattanKernel.tile + var r = 0 + var testarr: Array[Double] = Array.ofDim(tile.rows * tile.cols) + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + testarr(r * tile.rows + c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + print(testarr.reduce(_ + _)) + } + + test("octagon") { + val octagonKernel = octagon(3, false) + val tile = octagonKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("plus") { + val plusKernel = plus(3, false) + val tile = plusKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("prewitt") { + val prewittKernel = prewitt(false) + val tile = prewittKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("square") { + val squareKernel = square(3, false) + val tile = squareKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + + test("test add") { + val squareKernel1 = octagon(3, false, 100) + val tile1 = squareKernel1.tile + var r1 = 0 + while (r1 < tile1.rows) { + var c1 = 0 + val arr: Array[Double] = Array.ofDim(tile1.rows) + while (c1 < tile1.cols) { + arr(c1) = tile1.getDouble(c1, r1) + c1 += 1 + } + r1 += 1 + println(arr.toList) + } + println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++") + val squareKernel2 = octagon(5, false, 100) + val tile2 = squareKernel2.tile + var r2 = 0 + while (r2 < tile2.rows) { + var c2 = 0 + val arr: Array[Double] = Array.ofDim(tile2.rows) + while (c2 < tile2.cols) { + arr(c2) = tile2.getDouble(c2, r2) + c2 += 1 + } + r2 += 1 + println(arr.toList) + } + println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++") + val addsquareKernel = squareKernel1.add(squareKernel2) + val tile = addsquareKernel.tile + var r = 0 + while (r < tile.rows) { + var c = 0 + val arr: Array[Double] = Array.ofDim(tile.rows) + while (c < tile.cols) { + arr(c) = tile.getDouble(c, r) + c += 1 + } + r += 1 + println(arr.toList) + } + } + test("test inverse") { + val plusKernel1 = plus(5, false, 100) + val tile1 = plusKernel1.tile + var r1 = 0 + while (r1 < tile1.rows) { + var c1 = 0 + val arr: Array[Double] = Array.ofDim(tile1.rows) + while (c1 < tile1.cols) { + arr(c1) = tile1.getDouble(c1, r1) + c1 += 1 + } + r1 += 1 + println(arr.toList) + } + println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++") + val plusKernel2 = plusKernel1.inverse() + val tile2 = plusKernel2.tile + var r2 = 0 + while (r2 < tile2.rows) { + var c2 = 0 + val arr: Array[Double] = Array.ofDim(tile2.rows) + while (c2 < tile2.cols) { + arr(c2) = tile2.getDouble(c2, r2) + c2 += 1 + } + r2 += 1 + println(arr.toList) + } + } + + test("focal mean") { + val gaussianKernel = gaussianWithoutAmp(3, 1) + val multibandGeoTiff = GeoTiffReader.readMultiband(s"raster/data/geotiff-test-files/jpeg-test-deflate-small.tif") + val fmtile = multibandGeoTiff.tile.mapBands((_, tile) => tile.focalMean(gaussianKernel)) + MultibandGeoTiff(fmtile, multibandGeoTiff.extent, multibandGeoTiff.crs) + .write("raster/data/geotiff-test-files/jpeg-test-deflate-small-new.tif") + } + + +} From c030150bc7c66ed41ed5e934d53307ab12edcf0a Mon Sep 17 00:00:00 2001 From: yang162132 Date: Fri, 28 Oct 2022 10:03:58 +0800 Subject: [PATCH 2/2] add some kinds of kernel --- .../scala/geotrellis/raster/mapalgebra/focal/KernelSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raster/src/test/scala/geotrellis/raster/mapalgebra/focal/KernelSpec.scala b/raster/src/test/scala/geotrellis/raster/mapalgebra/focal/KernelSpec.scala index f2e0cf00e2..85381f7efc 100644 --- a/raster/src/test/scala/geotrellis/raster/mapalgebra/focal/KernelSpec.scala +++ b/raster/src/test/scala/geotrellis/raster/mapalgebra/focal/KernelSpec.scala @@ -23,7 +23,7 @@ import org.scalatest.funsuite.AnyFunSuite class KernelSpec extends AnyFunSuite { test("chebyshev") { - val chebyshevKernel = chebyshev(3) + val chebyshevKernel = chebyshev(5) val tile = chebyshevKernel.tile var r = 0 while (r < tile.rows) {