Half-Pixel Offset 究竟是个什么鬼?

友情提示 Half-Pixel Offset 其实算是个过时话题,请依据个人情况谨慎了解 :)

讲述之前我们先明确几个概念:

  • 窗口由正方形(注1)的像素(pixel)组成,每个像素只能显示一种颜色,并且像素坐标的原点在左上角像素的中心点(重要)

    以 3 * 3 的窗口为例

  • 纹理也是由正方形的纹素(texel)组成,每个纹素代表一种颜色,并且纹素坐标的原点在左上角纹素的左上角(重要)

    以 2 * 2 的纹理为例

  • 纹理的采样使用的是双线性(Bilinear)插值的方式(更多的细节可以看这里)

    以采样 2 * 2 的纹理的(0.5, 0.5)点为例

需要了解的概念就是这些,现在我们尝试在像素坐标的原点处绘制一个 2 * 2 大小的正方形,还记的像素坐标的原点是在像素的中心吗?我们想要绘制的正方形大概是这个样子:

示意图

由于像素是离散的,我们需要将绘制的正方形与像素尽可能的”对齐”(这里涉及到光栅化的规则,有兴趣的朋友可以去这里了解),所以实际绘制的正方形是这个样子的:

示意图

考虑到我们是从像素坐标的原点开始定义正方形的,所以上图所示的实际绘制结果也是符合预期的(正方形左上角与窗口左上角是对齐的)

现在我们想要将上面的纹理映射到刚才所绘制的正方形上去,为此我们需要为正方形的每个顶点计算纹素坐标,计算过程很简单,相关结果如下图所示:

示意图

简单想象一下,通过上面的纹理映射,我们期望得到的绘制结果是这个样子的:

示意图

但实际上,我们得到的绘制结果却是这个样子的:

示意图

什么鬼 ?

不急,我们来简单梳理一下~

回忆一下最开始需要绘制的的正方形示意图,我们在上面标注下纹素坐标:

示意图

根据上图中像素对应的纹素坐标,我们可以计算出像素对应的纹素颜色(此处我们没有详细讲解计算的方法,不清楚的朋友可以理解为取纹素坐标附近的四个像素的加权平均值即可):

计算公式

于是我们便得到了上面那个令人诧异的绘制结果~

怎么修正这个问题呢?

一种方法是直接偏移像素的纹素坐标,拿上面的正方形绘制为例,我们在采样纹素点(0, 0)时做一个(0.25, 0.25)的偏移,即采样(0 + 0.25, 0 + 0.25)点的纹理,这样我们便能采样到预期的纹理颜色了

不过更通用的做法,还是直接偏移顶点的像素坐标,仍然拿上面的正方形绘制举例,我们对正方形的各个顶点做一个(-0.5, -0.5)像素的偏移,那么实际绘制的正方形就是这个样子的:

示意图

此时,各个像素中点对应的纹素坐标如下图所示:

示意图

根据纹素坐标计算一下像素颜色即可发现我们采样到了预期的纹理颜色:

计算公式

而上述那么(-0.5, -0.5)的像素偏移,即是 Half-Pixel Offset

Half-Pixel Offset 只会在 Direct3D 9 及之前的Direct3D版本上出现,本质原因是像素坐标和纹素坐标定义不一致,OpenGL的像素坐标和纹素坐标定义是一致的,Direct3D 10以后也统一了像素坐标和纹素坐标的定义, Half-Pixel Offset 的问题也就不再存在了

如果你对于这个话题还有进一步了解的兴趣,可以再看看这里,这里,这里,和这里

注1 : 严格来讲,像素是点,而不是正方形
seg_json = "".join(["/data1/zhaoshutao/projectworkspace/nucleus_recognition/HEpng_img/testpy_spot_results/", args.Segjson]) low_scaleheight = args.lowscaleheight low_scalewidth = args.lowscalewidth offset_x = args.offsetx offset_y = args.offsety ####主要函数调用:获取spot的坐标*** print(sample,"\n---Main function call: get the coordinates of the spot---") print("seg_json: ", seg_json) print("scalefactors_json: ", scalefactors_json) print("tissue_positions_list: ", tissue_positions_file) print("low_scaleheight: %d \nlow_scalewidth: %d \noffset_x: %d \noffset_y: %d " % (low_scaleheight, low_scalewidth, offset_x, offset_y)) # 提取scalefactors_json.json中的信息 sfjson_data = read_json_file(scalefactors_json) scalefactor = sfjson_data.get('tissue_lowres_scalef') ### half_side = sfjson_data.get('spot_diameter_fullres') / 2 ### spotside = sfjson_data.get('spot_diameter_fullres') ## low图的高和宽,## 位移 original_coords_dict = hd2original(json_folder=seg_json, low_scaleheight=low_scaleheight, low_scalewidth=low_scalewidth, scalefactor= scalefactor, offset_x=offset_x, offset_y=offset_y) len(original_coords_dict) ##识别到的细胞数量 ## Align barcodes to spots colnames = ['in_tissue','x_array','y_array', 'x_pixel','y_pixel'] ## 输入文件:tissue_positions_list.csv包含至少三列:spot的barcode, x, y ## 提取spot的barcode,位置坐标x, y # 包含至少三列:spot的barcode, x, y spot_cell_count_pos = pd.read_csv(tissue_positions_file, delimiter = ',', header = None, index_col= 0) spot_cell_count_pos.columns = colnames # spot间区的中心坐标和相对坐标(用2/4相邻spot的barcode组合表示,'in_tissue'列用-1表示在spot间区) df_partition_cell_count = pd.DataFrame(data=None,columns=colnames) maxrow, maxcol = spot_cell_count_pos["x_array"].max(), spot_cell_count_pos["y_array"].max() print(maxrow, maxcol)帮我注释代码并看哪里会出问题?
最新发布
03-14
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值