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 = 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) } }