Hough transform: Difference between revisions
Content added Content deleted
(Kotlin entry) |
|||
Line 319: | Line 319: | ||
=={{header|Java}}== |
=={{header|Java}}== |
||
'''Code:''' |
'''Code:''' |
||
<lang Java>import java.awt.image.*; |
<lang Java>import java.awt.image.*; |
||
Line 467: | Line 466: | ||
<pre>java HoughTransform pentagon.png JavaHoughTransform.png 640 480 100</pre> |
<pre>java HoughTransform pentagon.png JavaHoughTransform.png 640 480 100</pre> |
||
<br style="clear:both" /> |
<br style="clear:both" /> |
||
=={{header|Kotlin}}== |
|||
{{trans|Java}} |
|||
<lang scala>import java.awt.image.* |
|||
import java.io.File |
|||
import javax.imageio.* |
|||
internal class ArrayData(val dataArray: IntArray, val width: Int, val height: Int) { |
|||
constructor(width: Int, height: Int) : this(IntArray(width * height), width, height) { |
|||
} |
|||
operator fun get(x: Int, y: Int) = dataArray[y * width + x] |
|||
operator fun set(x: Int, y: Int, value: Int) { |
|||
dataArray[y * width + x] = value |
|||
} |
|||
operator fun invoke(thetaAxisSize: Int, rAxisSize: Int, minContrast: Int): ArrayData { |
|||
val maxRadius = Math.ceil(Math.hypot(width.toDouble(), height.toDouble())).toInt() |
|||
val halfRAxisSize = rAxisSize.ushr(1) |
|||
val outputData = ArrayData(thetaAxisSize, rAxisSize) |
|||
// x output ranges from 0 to pi |
|||
// y output ranges from -maxRadius to maxRadius |
|||
val sinTable = DoubleArray(thetaAxisSize) |
|||
val cosTable = DoubleArray(thetaAxisSize) |
|||
for (theta in thetaAxisSize - 1 downTo 0) { |
|||
val thetaRadians = theta * Math.PI / thetaAxisSize |
|||
sinTable[theta] = Math.sin(thetaRadians) |
|||
cosTable[theta] = Math.cos(thetaRadians) |
|||
} |
|||
for (y in height - 1 downTo 0) |
|||
for (x in width - 1 downTo 0) |
|||
if (contrast(x, y, minContrast)) |
|||
for (theta in thetaAxisSize - 1 downTo 0) { |
|||
val r = cosTable[theta] * x + sinTable[theta] * y |
|||
val rScaled = Math.round(r * halfRAxisSize / maxRadius).toInt() + halfRAxisSize |
|||
outputData.accumulate(theta, rScaled, 1) |
|||
} |
|||
return outputData |
|||
} |
|||
fun writeOutputImage(filename: String) { |
|||
val max = dataArray.max()!! |
|||
val image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) |
|||
for (y in 0..height - 1) |
|||
for (x in 0..width - 1) { |
|||
val n = Math.min(Math.round(this[x, y] * 255.0 / max).toInt(), 255) |
|||
image.setRGB(x, height - 1 - y, n shl 16 or (n shl 8) or 0x90 or -0x01000000) |
|||
} |
|||
ImageIO.write(image, "PNG", File(filename)) |
|||
} |
|||
private fun accumulate(x: Int, y: Int, delta: Int) { |
|||
set(x, y, get(x, y) + delta) |
|||
} |
|||
private fun contrast(x: Int, y: Int, minContrast: Int): Boolean { |
|||
val centerValue = get(x, y) |
|||
for (i in 8 downTo 0) |
|||
if (i != 4) { |
|||
val newx = x + i % 3 - 1 |
|||
val newy = y + i / 3 - 1 |
|||
if (newx >= 0 && newx < width && newy >= 0 && newy < height |
|||
&& Math.abs(get(newx, newy) - centerValue) >= minContrast) |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
} |
|||
internal fun readInputFromImage(filename: String): ArrayData { |
|||
val image = ImageIO.read(File(filename)) |
|||
val w = image.width |
|||
val h = image.height |
|||
val rgbData = image.getRGB(0, 0, w, h, null, 0, w) |
|||
// flip y axis when reading image |
|||
val array = ArrayData(w, h) |
|||
for (y in 0..h - 1) |
|||
for (x in 0..w - 1) { |
|||
var rgb = rgbData[y * w + x] |
|||
rgb = ((rgb and 0xFF0000).ushr(16) * 0.30 + (rgb and 0xFF00).ushr(8) * 0.59 + (rgb and 0xFF) * 0.11).toInt() |
|||
array[x, h - 1 - y] = rgb |
|||
} |
|||
return array |
|||
} |
|||
fun main(args: Array<out String>) { |
|||
val inputData = readInputFromImage(args[0]) |
|||
val minContrast = if (args.size >= 4) 64 else args[4].toInt() |
|||
inputData(args[2].toInt(), args[3].toInt(), minContrast).writeOutputImage(args[1]) |
|||
}</lang> |
|||
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
=={{header|Mathematica}} / {{header|Wolfram Language}}== |