48MP 手机只拍出 12MP,少的 36MP 去哪了?5 种传感器算给你看
4800 万像素的传感器,默认拍出来的照片只有 1200 万像素。
少的 3600 万没有丢,是每 4 个同色像素合成 1 个输出像素。
我把 5 种手机传感器的规格做成了一个单文件网页,加载时自动跑 15 条断言,15/15 通过。
![]()
在线案例与源码:https://atomgit.com/deli007/demo_park/tree/main/codearts-pixel-binning-lab
成品只有一个index.html,双击就能打开;页面不联网,也不上传任何数据。
这不是拍照教程,也不评价哪台手机拍照好。页面上只算一件事:像素怎么合并,数字怎么变。
一、为什么值得看:4800 万和 1200 万,差的就是 4 倍
8000 乘 6000 等于 48,000,000。
4000 乘 3000 等于 12,000,000。
两个数字一比,正好是 4 倍。
所以 4800 万像素的传感器默认输出 1200 万,少的 3600 万并不是被裁掉了。
它换了一种记账方式:4 个像素只交 1 份结果。
普通 Bayer 阵列里,每个 2×2 方块是 R、G、G、B 各一个。
Quad Bayer 把同色像素排在一起,变成 2×2 的 R、2×2 的 G、2×2 的 B。
![]()
合并时,一个 2×2 同色块只输出 1 个像素。
4800 万的阵列,就这样变成了 4000×3000。
单个像素的尺寸是 0.8 微米,4 个合成 1 个,等效尺寸变成 1.6 微米。
感光面积从 0.64 平方微米变成 2.56 平方微米,正好 4 倍。
这就是手机默认拍 1200 万的原因:像素少了,但每个输出像素进光更多。
二、准备环境:进入码道 Web
浏览器打开码道 Web 版,登录后在对话框里写需求:
码道有三种使用方式:WebUI、TUI 和桌面 IDE。本文用 WebUI 版演示。
不用装软件,也不需要先开通什么。
三、需求原文:把期望值写死在需求里
这一轮我没有让模型自己回忆参数。
6 组传感器的宽高、合并倍数、等效尺寸,15 条断言,我一条条写进需求。
原因很直接:像素数的乘法没有创作空间,写错一个数字,整页都不可信。
需求的主干是这样:
做一个单文件网页「像素合并实验室」,样式和脚本内联,不引用外部资源。
预设:48MP 0.8um 8000x6000,4 合 1 输出 4000x3000;
50MP 1.0um 8160x6144,4 合 1 输出 4080x3072;
64MP 0.8um 9248x6936,4 合 1 输出 4624x3468;
108MP 0.8um 12000x9000,9 合 1 输出 4000x3000;
200MP 0.56um 16384x12288,16 合 1 输出 4096x3072;
12MP 1.4um 参考 4000x3000,不合并。
输入非法时给出中文提示,并保留上一次的有效结果。
页面加载时跑 15 条断言,全部通过才显示 15/15。
完成后打开预览。
最后一句「完成后打开预览」很关键。
它让我在同一个页面里看到成品,省掉先部署再看的往返。
四、实测:5 种传感器,输出都落在 1200 万到 1600 万之间
我把 6 个预设逐个点了一遍,读数如下。
| 传感器 | 物理宽×高 | 标称像素 | 合并 | 输出像素 | 等效尺寸 | 信噪比 | 12bit RAW |
|---|---|---|---|---|---|---|---|
| 48MP 0.8μm | 8000×6000 | 48,000,000 | 4 合 1 | 4000×3000 / 12,000,000 | 1.60μm | +6.02dB | 72.00MB |
| 50MP 1.0μm | 8160×6144 | 50,135,040 | 4 合 1 | 4080×3072 / 12,533,760 | 2.00μm | +6.02dB | 75.20MB |
| 64MP 0.8μm | 9248×6936 | 64,144,128 | 4 合 1 | 4624×3468 / 16,036,032 | 1.60μm | +6.02dB | 96.22MB |
| 108MP 0.8μm | 12000×9000 | 108,000,000 | 9 合 1 | 4000×3000 / 12,000,000 | 2.40μm | +9.54dB | 162.00MB |
| 200MP 0.56μm | 16384×12288 | 201,326,592 | 16 合 1 | 4096×3072 / 12,582,912 | 2.24μm | +12.04dB | 301.99MB |
| 12MP 1.4μm | 4000×3000 | 12,000,000 | 不合并 | 4000×3000 / 12,000,000 | 1.40μm | 0.00dB | 18.00MB |
这张表里最容易被忽略的是 64MP。
它的 4 合 1 输出是 4624×3468,等于 1603 万,不是 1200 万。
所以「默认输出 1200 万」是多数机型的做法,不是所有 4 合 1 的固定结果。
108MP 走的是 9 合 1,3×3 同色块合成 1 个,12000×9000 正好变成 4000×3000。
200MP 走 16 合 1,4×4 合成 1 个,输出 4096×3072。
![]()
输出像素都围着 1200 万转,这不是巧合。
手机厂把默认输出定在 12MP 左右,是在分辨率和进光量之间取平衡。
信噪比那一列也能对上。
4 合 1 提升 10log10(4),等于 6.02dB。
9 合 1 提升 9.54dB,16 合 1 提升 12.04dB。
这里的 dB 是相对同一颗传感器的单像素读数,只考虑散粒噪声。
和 12MP 1.4μm 参考比,48MP 合并后的面积是 1.31 倍,108MP 是 2.94 倍,200MP 是 2.56 倍。
![]()
打印尺寸和 RAW 体积也一起算了。
48MP 在 300DPI 下是 26.67×20.00 英寸,合并后是 13.33×10.00 英寸。
200MP 全分辨率能到 54.61×40.96 英寸,合并后回到 13.65×10.24 英寸。
12bit 无压缩 RAW,48MP 是 72MB,12MP 是 18MB,200MP 是 301.99MB。
页面里的 1MB 按 1,000,000 字节计,所以这些数字可以直接复算。
五、验证与踩坑:15 条断言,两个真问题
页面的自检面板在加载时跑 15 条断言,当前是 15/15 通过。
里面不是「页面能打开」这种空话,而是具体乘法:
- 8000×6000 = 48,000,000
- 4 合 1 输出 4000×3000 = 12,000,000
- 108MP 9 合 1 输出 = 12,000,000
- 200MP 16 合 1 输出 = 12,582,912
- 0.8×3 = 2.4
- 8000÷300 = 26.67
- 48MP 12bit RAW = 72.00MB
我在浏览器里点了 108MP、200MP,也把输入框改成 abc。
第一个真问题出在联动上。
选中 108MP 后,顶部已经变成 12000×9000,下面的自定义面板还停在 8000×6000。
原因是自定义面板读的是上一次的自定义值,切换预设时没有同步。
修法很短:切预设时把输入框和自定义结果一起重算。
第二个真问题是 64MP 那行的乘积。
模型写的是 16,032,768,按 4624×3468 重算应为 16,036,032。
差了 3,264,肉眼很容易漏掉。
我把页面改成按宽高现算,不再信任手写的总数。
失败路径也单独试了。
输入 abc,页面给出「请输入大于 0 的像素数或宽x高」,并保留上一次的 16384×12288。
![]()
六、使用码道体会:把验收写成数字
- 需求里先写死期望值,再让模型画界面。
- 断言要写进页面,不要只写在对话里。
- 让页面按宽高现算,不要让它手写乘好的总数。
- 每加一个交互,就回头点一次,联动最容易断。
- 15/15 通过只说明这 15 条成立,不说明界面好看。
- 预览要自己滚到底,首屏正常不等于整页正常。
七、边界与下一步
这篇没有拍真实照片,也没有对比不同手机的成像。
页面算的是像素账,不是画质排名。
48MP 全分辨率模式还有一步 remosaic:把 2×2 同色块重新排成 Bayer 阵列,靠插值补缺失颜色。
所以 4800 万模式的有效细节,通常明显低于像素数的 4 倍。
信噪比的 +6.02dB 也是理想值,只考虑散粒噪声。
读出噪声、降噪算法、镜头素质都会把它拉低。
下一步可以加一张分辨率测试卡,把 remosaic 的损失也画出来。
八、亲手点三下
看尺子:选中 48MP,确认顶部是 4800 万变 1200 万,等效 1.60 微米。
换输入:点 200MP,看它变成 16 合 1、2.24 微米。
看失败路径:在自定义输入里敲 abc,必须看到中文提示,且上一次的数值还在。
直接下载试玩
源码在 Demo Park:https://atomgit.com/deli007/demo_park/tree/main/codearts-pixel-binning-lab
本地复现:
git clone https://atomgit.com/deli007/demo_park.git
cd demo_park/codearts-pixel-binning-lab
start index.html
打开后就是完整页面,不需要装依赖,也不需要起服务。
- 点赞
- 收藏
- 关注作者
评论(0)