图片切九宫格的像素坐标计算逻辑

用宽高和索引确定九宫格边界

图片切九宫格的核心不是把宽高简单除以 3,而是为 3 列、3 行分别计算边界。只要边界采用整数坐标,并保证相邻区域首尾相接,就能让 9 个区域完整覆盖原图,每个像素只被裁剪一次。

设原图宽度为 W、高度为 H,坐标原点位于左上角,横坐标向右增加,纵坐标向下增加。九宫格固定为 3 列 × 3 行,共 9 个区域,行号 r 和列号 c 的取值都为 0、1、2。

  • r=0 表示第一行,r=2 表示第三行。
  • c=0 表示第一列,c=2 表示第三列。
  • 裁剪框使用半开区间 [x1,x2) × [y1,y2),包含左、上边界,不包含右、下边界。

在这种坐标约定下,第 r 行、第 c 列区域的基础计算公式为:

  • x1=floor(cW/3)
  • x2=floor((c+1)W/3)
  • y1=floor(rH/3)
  • y2=floor((r+1)H/3)

例如,第一行第二列对应 r=0、c=1,因此横向范围是 [floor(W/3), floor(2W/3)),纵向范围是 [0, floor(H/3))。

非整除宽高的余数分配与像素对齐

当 W 或 H 不能被 3 整除时,三等分结果不是整数。若直接使用浮点坐标,例如把边界写成 333.33,就会遇到半像素、重复取整或区域之间出现缝隙的问题。图像像素必须落在整数网格上,因此应先生成整数边界,再执行裁剪。

常见做法有两类:

  • 累计取整:直接计算边界序列 floor(0W/3)、floor(1W/3)、floor(2W/3)、floor(3W/3)。高度方向使用同样规则。
  • 商余数分配:先计算 W=3q+s,其中 q 是商、s 是余数,再把余数分给前 s 列。高度方向同理。

两种方式在合理实现下都能得到整数区域。累计边界的优点是公式直接,并且天然保证相邻区域的前一个 x2 等于后一个 x1;三个区域的宽度相加必然等于 W,高度相加必然等于 H。

以宽度 W=1000 为例,横向边界为 0、333、666、1000,三列宽度分别是 333、333、334。最后一列多 1 个像素并不是错误,而是余数的分配结果。

完整尺寸为 1000×701 像素时,按累计取整计算,宽度边界仍为 0、333、666、1000,高度边界为 0、233、467、701。对应的行高是 233、234、234。因此,不能把“9 张图尺寸完全相同”作为正确性的必要条件;正确目标是覆盖完整且不重复。

裁剪接口中的坐标参数与边界检查

一个裁剪框通常包含四个坐标:左坐标 x1、上坐标 y1、右坐标 x2、下坐标 y2。在半开区间规则下,输出尺寸为 (x2-x1) × (y2-y1)。

每个区域执行裁剪前,应检查以下条件:

  • 0≤x1<x2≤W
  • 0≤y1<y2≤H
  • 相邻列满足前一块的 x2 等于后一块的 x1。
  • 相邻行满足上一块的 y2 等于下一块的 y1。

不同接口不一定使用右下坐标。有的 API 接收 x1,y1,x2,y2,有的接收左上坐标加宽高,例如 x,y,width,height。遇到后一种形式,应先换算为 x2=x+width、y2=y+height,再检查是否越界。

  • Pillow:Image.crop() 常见用法是传入四元组框坐标,具体边界行为应以所用版本文档为准。
  • OpenCV:数组切片通常写成 image[y1:y2, x1:x2],行坐标在前,列坐标在后,属于半开区间写法。
  • Canvas API:drawImage() 可使用源图起点、源区域宽高等参数,右下边界需要由起点和宽高换算,实际采样还可能受到缩放和插值影响。

不要把这些接口的坐标规则当成统一标准。尤其是右边界、下边界是否包含,取决于具体 API;使用半开区间时,前一块的右边界正好是后一块的左边界,不会重复裁剪。

结合在线工具验证九宫格裁剪结果

使用“图片切九宫格”时,可以按下面的流程检查结果:

  1. 上传原图,记录图片的实际宽度 W 和高度 H。
  2. 选择 3×3 切分,确认预览中有 9 个输出区域。
  3. 下载结果,逐张记录文件尺寸,并将列宽、行高分别相加。
  4. 用带余数的尺寸测试,例如 1000×701,检查列宽是否为 333、333、334,行高是否为 233、234、234 或其他同样满足总和的分配方式。
  5. 将 9 张图按原来的行列顺序拼接,确认恢复后的尺寸仍为 1000×701,并检查边界像素没有重复或缺失。

工具的具体余数分配方式、输出图片格式和压缩行为取决于实现,不能默认所有在线工具都采用“余数放到最后一列和最后一行”。例如,有些实现把余数分给前几列,有些实现通过累计边界让最后一个区域承担余数;只要覆盖完整且区域不重叠,结果都可以成立。

九宫格的边界归属问题可以用一句规则判断:半开区间下,像素坐标小于右边界、下边界才属于当前区域。若工具采用左上角加宽高参数,则先换算出右下坐标,再检查 9 个框是否满足范围约束;不要为了追求相同尺寸而强行裁掉余数像素。

更多推荐

亮度/对比度调整看似只是拖动滑块,实际是在重排像素值。线性变换均匀改变整个亮度范围,S 型曲线则把对比度集中到特定区域;两者对暗部、亮部细节的影响并不相同。 先用灰度映射看懂两种调法 可以把灰度调整理解为一张“输入—输出”对照表:输入像

了解更多 >

先把比较条件锁死:9×9 核不等于同样强度 均值模糊和高斯模糊都能让图片变软,但它们在文字边缘、细线和高对比度轮廓上的表现不同。要看出差异,不能只比较缩略图,而要固定图像、核尺寸、边界处理和输出格式,再观察局部细节与实际耗时。 使用同一张

了解更多 >

先区分方向标签与图像像素 EXIF Orientation 是 JPEG 中记录“应该怎样显示”的方向标签,不等于文件里的像素已经旋转。处理照片时,必须把文件内的像素坐标、查看器执行的显示变换,以及导出时是否重写像素分开判断。 EXIF

了解更多 >

两种“补色”算法为何结果不同 “补色”在图像处理中可能指两套不同规则:一套是对 RGB 通道做数值反转,另一套是沿 HSL 色轮把色相移动 180°。它们对纯红等高饱和颜色可能得到相同或相近结果,但面对灰色、低饱和色和不同明度的颜色,视觉结

了解更多 >

彩色图片转成灰度图后层次变弱,通常不是“变黑”,而是不同颜色被压缩到同一条亮度轴上。补偿的目标是重新分配已有灰度值:用伽马校正调整暗部和中间调,用直方图拉伸扩大有效亮度范围;它们不能恢复已经丢失的色相信息。 说明灰度转换为何会损失对比度

了解更多 >