为"我们的照片与官方照片到底差在哪"提供可量化的手段,而不是靠肉眼看图: - FrameProfile:对 160x120 载荷算行/列均值的步进与 3 抽头高频,并给出 「列高频 / 行高频」比值——列固定图案噪声会表现为该比值显著 >1,场景内容则接近 1。 同时对压缩块与"官方布局"(DDT 头 + 884B BasePara + 帧)都能定位载荷。 - NucDump:把 NUC 块按线性映射直出 PNG,用来判断成品图里的结构是"数据里有" 还是"显示级引入的"。 - StripeCheck:在成品图的平坦区域量列抖动,并给出它占局部量程的百分比。 实测结论(本轮):我们的原始帧列高频 675 counts(列噪声主导,符合未校正预期), 而我们的 NUC 块只有 4.1 counts、行/列比 1.25,且成品图上平坦区列抖动仅为局部量程的 0.1% —— 即**校正后没有残留列噪声**,肉眼以为的竖纹是场景纹理。官方的成品帧(其文件 存的是校正后数据)同样干净(colHF 5.5、比值 1.39),两边校正质量等价。 .tmp-*/ 加入忽略:对比用的用户照片与中间产物放在那里,不入库。
26 lines
1.2 KiB
Java
26 lines
1.2 KiB
Java
import java.awt.image.BufferedImage;
|
|
import java.io.File;
|
|
import javax.imageio.ImageIO;
|
|
/** Column-jitter (stripe) amplitude inside a flat region of a rendered photo. */
|
|
public class StripeCheck {
|
|
public static void main(String[] a) throws Exception {
|
|
BufferedImage im = ImageIO.read(new File(a[0]));
|
|
int x0 = Integer.parseInt(a[1]), y0 = Integer.parseInt(a[2]);
|
|
int w = Integer.parseInt(a[3]), h = Integer.parseInt(a[4]);
|
|
double[] col = new double[w];
|
|
double lo = 255, hi = 0;
|
|
for (int y = y0; y < y0 + h; y++)
|
|
for (int x = x0; x < x0 + w; x++) {
|
|
int c = im.getRGB(x, y);
|
|
int l = (((c >> 16) & 0xFF) * 299 + ((c >> 8) & 0xFF) * 587 + (c & 0xFF) * 114) / 1000;
|
|
col[x - x0] += l; if (l < lo) lo = l; if (l > hi) hi = l;
|
|
}
|
|
for (int i = 0; i < w; i++) col[i] /= h;
|
|
double hf = 0; int n = 0;
|
|
for (int i = 1; i < w - 1; i++) { hf += Math.abs(col[i] - (col[i-1] + col[i+1]) / 2); n++; }
|
|
hf /= n;
|
|
System.out.printf("%-28s region %dx%d luma %.0f..%.0f (range %.0f) colJitter=%.2f = %.1f%% of local range%n",
|
|
new File(a[0]).getName(), w, h, lo, hi, hi - lo, hf, 100 * hf / Math.max(1, hi - lo));
|
|
}
|
|
}
|