package com.example.mini_tias
import java.nio.ShortBuffer
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* [ImageStatistics] の数理ロジック(mean/max/p99/飽和率・低露光率)の単体テスト.
*
* 合成した 10-bit BGGR Bayer データを `computeFromShortBuffer` に与えて期待値を検証する.
* 実機・Android Framework に依存しない純粋な JVM テスト(実行: `./gradlew test`).
*
* BGGR 配列の 2×2 ブロック走査:
* (row, col) 偶数行: B G B G ...
* 奇数行: G R G R ...
* 1 ブロック = B=(0,0), G=(0,1), G=(1,0), R=(1,1).G はブロック内 2 サンプルの平均.
*/
class ImageStatisticsTest {
private fun compute(values: ShortArray, width: Int, height: Int): Map<String, Any?> =
ImageStatistics.computeFromShortBuffer(
ShortBuffer.wrap(values),
width, // rowStrideShorts(パディングなし)
width,
height,
)
@Test
fun `一様な値の場合 mean と max が一致し飽和・低露光は 0 になる`() {
// 4×4 すべて 500
val values = ShortArray(16) { 500 }
val result = compute(values, 4, 4)
val mean = result["mean_per_channel"] as Map<*, *>
assertEquals(500.0, mean["R"] as Double, 1e-9)
assertEquals(500.0, mean["G"] as Double, 1e-9)
assertEquals(500.0, mean["B"] as Double, 1e-9)
val max = result["max_per_channel"] as Map<*, *>
assertEquals(500, max["R"] as Int)
assertEquals(500, max["G"] as Int)
assertEquals(500, max["B"] as Int)
assertEquals(0.0, result["saturated_pixel_ratio"] as Double, 1e-9)
assertEquals(0.0, result["underexposed_pixel_ratio"] as Double, 1e-9)
// p99: 500 は bin 125(500*256/1024)→ (125+1)*1024/256 - 1 = 503
val p99 = result["p99_per_channel"] as Map<*, *>
assertEquals(503, p99["R"] as Int)
assertEquals(503, p99["G"] as Int)
assertEquals(503, p99["B"] as Int)
}
@Test
fun `飽和画素と低露光画素がチャネル別 mean・max・比率に正しく反映される`() {
// 4×4.左上ブロックの B=1000(飽和), G の片側=50(低露光).他はすべて 500.
// row0: 1000 50 500 500
// row1: 500 500 500 500
// row2: 500 500 500 500
// row3: 500 500 500 500
val values = shortArrayOf(
1000, 50, 500, 500,
500, 500, 500, 500,
500, 500, 500, 500,
500, 500, 500, 500,
)
val result = compute(values, 4, 4)
val mean = result["mean_per_channel"] as Map<*, *>
// B: (1000+500+500+500)/4 = 625
assertEquals(625.0, mean["B"] as Double, 1e-9)
// G: ((50+500)/2 + 500 + 500 + 500)/4 = (275+1500)/4 = 443.75
assertEquals(443.75, mean["G"] as Double, 1e-9)
// R: すべて 500
assertEquals(500.0, mean["R"] as Double, 1e-9)
val max = result["max_per_channel"] as Map<*, *>
assertEquals(1000, max["B"] as Int)
assertEquals(500, max["R"] as Int)
// 飽和は B=1000 の 1 画素,低露光は G=50 の 1 画素.総 Bayer 画素 = 16.
assertEquals(1.0 / 16.0, result["saturated_pixel_ratio"] as Double, 1e-9)
assertEquals(1.0 / 16.0, result["underexposed_pixel_ratio"] as Double, 1e-9)
val thresholds = result["thresholds"] as Map<*, *>
assertEquals(1000, thresholds["saturated"] as Int)
assertEquals(100, thresholds["underexposed"] as Int)
}
}