如何在不造成像素重叠的情况下缩小块
How to scale down blocks without causing pixel overlapping
我有一堆需要绘制成网格的块。现在显示它们没有缩放,一切都很好,但是当我试图缩小它们以适应一个窗口时,我得到了"缩放伪影",因为我使用了正常的缩放比例公式和浮动。
有办法避免这些问题吗?
常用示例数据:
Original length: 200000
缩小到25x25 pixel grid
(对于开发和调试来说只有这么小)缩放后的最大长度:625 (25 * 25)
Scale-ratio: (625 / 200000) = 0,003125
示例数据1 -重叠,缩放块相互覆盖[Start, end]
1: 2100 => 2800
2: 2800 => 3600
3: 3600 => 4500
4: 4500 => 5500
跳过这个例子的输出,因为我认为例子2和3会让你明白这一点。为了完整留了下来。
示例数据2 - 2和3之间空格错误[Start, end]
1: 960 => 1440
2: 1440 => 1920
3: 1920 => 2400
1: 960 => 1440, length: 480, scaled length: 1.5:
2: 1440 => 1920, length: 480, scaled length: 1.5:
3: 1920 => 2400, length: 480, scaled length: 1.5:
像素起始,结束,长度
1: 3, 0, 1
2: 4, 0, 1
3: 6, 0, 1
显示网格:
[ 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
...
示例数据3 - 1错误地向后移动了一步[Start, end]
1: 896 => 1344
2: 1344 => 1792
3: 1792 => 2240
1: 896 => 1344, length: 448, scaled length: 1.4:
2: 1344 => 1792, length: 448, scaled length: 1.4:
3: 1792 => 2240, length: 448, scaled length: 1.4:
像素起始,结束,长度
1: 2, 0, 1
2: 4, 0, 1
3: 5, 0, 1
显示网格:
[ 0, 0, 1, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
...
数据2和3应该是什么样子?
[ 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
...
记住块值是[start, end)
先发制人(down-voters/trollers)记住:我不是通灵者或读心术者。
如果你想给负面的,以一种紧缩的方式去做,否则它是无用的(我不会学到任何东西),只会污染线程。#include <iostream>
#include <math.h>
#include <limits.h>
#include <assert.h>
#include <vector>
#include <array>
#include <utility> // pair
#include <algorithm> // for_each
using namespace std;
const size_t width_size = 25; // 25 pixels
const size_t height_size = 25; // 25 pixels
const size_t grid_length = width_size * height_size; // width * height
array<size_t, grid_length> grid;
const size_t original_length = 200000;
typedef pair<unsigned long, unsigned long> block;
vector<block> test_values;
void show_grid()
{
for (size_t y = 0; y < height_size; ++y) {
const size_t start_pos_for_current_heigth = y * width_size;
const size_t end_pos_for_current_heigth = start_pos_for_current_heigth + width_size;
cout << "[ ";
for (size_t i = start_pos_for_current_heigth; i < end_pos_for_current_heigth; ++i) {
if (i + 1 < end_pos_for_current_heigth)
cout << grid[i] << ", ";
else
cout << grid[i];
};
cout << " ]" << endl;
}
}
void scale_and_add(const float scale)
{
size_t test_value_id = 1;
for_each(test_values.cbegin(), test_values.cend(), [&](const block &p) {
const float s_f = p.first * scale;
const unsigned long s = round(s_f);
const float e_f = p.second * scale;
const unsigned long e = round(e_f);
const unsigned long block_length = p.second - p.first;
const float block_length_scaled = block_length * scale;
assert(s <= grid_length);
assert(e <= grid_length);
cout << test_value_id << ":" << endl;
cout << " " << p.first << " => " << p.second << " length: " << block_length << endl;
cout << " " << s << " (" << s_f << ") => " << e << " (" << e_f << ") length: " << (e - s) << " (" << block_length_scaled << ")" << " (scaled)" << endl;
for (size_t i = s; i < e; ++i) {
if (grid[i] != 0) {
cout << "overlapp detected !" << endl;
}
grid[i] = test_value_id;
}
++test_value_id;
});
}
void reset_common()
{
grid.fill(0);
test_values.clear();
}
int main()
{
const float scale = ((float)grid_length / (float)original_length);
cout << "scale: " << scale << " length per pixel: " << ((float)original_length / (float)grid_length) << endl;
// Example data 1
/* cout << "Example data 1" << endl;
test_values.push_back(make_pair(2100, 2800));
test_values.push_back(make_pair(2800, 3600));
test_values.push_back(make_pair(3600, 4500));
test_values.push_back(make_pair(4500, 5500));
scale_and_add(scale);
show_grid();
reset_common();
// Example data 2
cout << "Example data 2" << endl;
test_values.push_back(make_pair(960, 1440));
test_values.push_back(make_pair(1440, 1920));
test_values.push_back(make_pair(1920, 2400));
scale_and_add(scale);
show_grid();
reset_common();
// Example data 3
cout << endl << "Example data 3" << endl;
test_values.push_back(make_pair(896, 1344));
test_values.push_back(make_pair(1344, 1792));
test_values.push_back(make_pair(1792, 2240));
scale_and_add(scale);
show_grid();
reset_common();*/
// Generated data - to quickly find the problem
cout << "Generated data" << endl;
auto to_op = [&](const size_t v) {
return v * (original_length / grid_length) * 1.3; // 1.4 and 1.5 are also good values to show the problem
};
size_t pos = 0;
size_t psize = 1; // Note this value (length) and check it with the displayed one, you'll be surprised !
for (size_t g = 0; g < 10; ++g) {
test_values.push_back(make_pair(to_op(pos), to_op(pos + psize)));
pos += psize;
}
scale_and_add(scale);
show_grid();
return 0;
}
输出:scale: 0.003125 length per pixel: 320
Generated data
1:
0 => 416 length: 416
0 (0) => 1 (1.3) length: 1 (1.3) (scaled)
2:
416 => 832 length: 416
1 (1.3) => 3 (2.6) length: 2 (1.3) (scaled)
3:
832 => 1248 length: 416
3 (2.6) => 4 (3.9) length: 1 (1.3) (scaled)
4:
1248 => 1664 length: 416
4 (3.9) => 5 (5.2) length: 1 (1.3) (scaled)
5:
1664 => 2080 length: 416
5 (5.2) => 7 (6.5) length: 2 (1.3) (scaled)
6:
2080 => 2496 length: 416
7 (6.5) => 8 (7.8) length: 1 (1.3) (scaled)
7:
2496 => 2912 length: 416
8 (7.8) => 9 (9.1) length: 1 (1.3) (scaled)
8:
2912 => 3328 length: 416
9 (9.1) => 10 (10.4) length: 1 (1.3) (scaled)
9:
3328 => 3744 length: 416
10 (10.4) => 12 (11.7) length: 2 (1.3) (scaled)
10:
3744 => 4160 length: 416
12 (11.7) => 13 (13) length: 1 (1.3) (scaled)
[ 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
这个代码示例更清楚地说明了我的问题。
有趣的事实:我用来编写这个例子的mingw-g++显示的值略有不同。我通常使用visual studio 2010,但这次不能,因为我不在家。我不确定我是否得到了问题陈述,但我会尝试一下。您有连续显示的信息范围,范围通常是[a,b)。当a和b直接表示你想要绘制的像素时,一切都很好,但是当你想要缩放整个东西时,你就会遇到问题。
不处理多行像素,如果你有两个范围R1=[a,b)和R2=[b,c)未缩放,你只是从a绘制到b-1和从b绘制到c-1,你的范围被绘制,那么缩放情况下的问题是什么从(int)(a*scale)到((b*scale)-1),然后从(int)(b*scale)到((int)(c*scale)-1),你可以使用任何float到int转换,四舍五入,地板或天花板,你应该ok。
下一个问题是,如果缩放范围小于1个像素,在这种情况下,您可能需要检测缩放范围的大小是否为0,并在计算结束时添加一个校正因子(以像素为单位)。
伪代码DrawRanges(List<Range> ranges, float scale)
int carry = 0;
foreach(Range range in ranges)
{
int newStart = ceiling(range.start*scale);
int newEnd = ceiling(range.end*scale)-1;
if (newStart <= newEnd)
{
newEnd = newStart;
++carry;
}
DrawRange(newStart+carry,newEnd+carry);
}
这将最终失败,如果你有更多的范围比块在你的缩放网格,你将不得不弄清楚如何完全放弃范围。在drawrange中,你将索引映射到一个实际的块坐标。
这解决你的问题了吗?
对,再加1,问题没问题。我不知道为什么人们认为不留下评论就投反对票很有趣。
好吧,对于这个问题:-)
通常在绘图时你会遇到这种重叠问题,在3D计算机图形中使用扫描线渲染器(DirectX &在OpenGL中,它们通常会跳过一个像素(即右侧和下方的所有像素)。也许这能帮到你。
也有可能当除法是完美的时候,你没有人工制品,所以你可能必须处理它(即。如果值是一个'完全整数',例如185.000000,则不要删除最后一个像素)。
HTH
- 在没有太多条件句的情况下,我如何避免被零除
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 在未初始化映射的情况下,将值插入到映射的映射中
- 是默认情况下分配给char数组常量的值
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 如何在不产生任何垃圾的情况下获得C中的像素
- 在已经使用Git的情况下减少编译时间
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 如何在没有信号的情况下从C++执行QML插槽
- 如何在不知道向量大小的情况下输入向量内部的向量?
- 为什么在某些情况下不写入此文件?
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 在没有Xcode的情况下在Mac捆绑包中嵌入框架
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 在这种情况下,我应该为每个WSASend调用传递唯一的重叠结构吗?
- 多个线程/进程是否可以在不同步的情况下同时从/写入文件的非重叠区域?
- 在给定两个区间列表的情况下,得到重叠区间的数量
- 如何在不使数字重叠的情况下生成 1 - 39 的随机数
- 如何在不造成像素重叠的情况下缩小块