I want to optimize this code, in particular this function:
bool interpolate(const Mat &im, float ofsx, float ofsy, float a11, float a12, float a21, float a22, Mat &res)
{
bool ret = false;
// input size (-1 for the safe bilinear interpolation)
const int width = im.cols-1;
const int height = im.rows-1;
// output size
const int halfWidth = res.cols >> 1;
const int halfHeight = res.rows >> 1;
int dim = res.rows * res.cols;
float *out = res.ptr<float>(0);
for (int j=-halfHeight; j<=halfHeight; ++j)
{
const float rx = ofsx + j * a12;
const float ry = ofsy + j * a22;
#pragma omp simd
for(int i=-halfWidth; i<=halfWidth; ++i)
{
float wx = rx + i * a11;
float wy = ry + i * a21;
const int x = (int) floor(wx);
const int y = (int) floor(wy);
if (x >= 0 && y >= 0 && x < width && y < height)
{
// compute weights
wx -= x; wy -= y;
// bilinear interpolation
*out++ =
(1.0f - wy) * ((1.0f - wx) * im.at<float>(y,x) + wx * im.at<float>(y,x+1)) +
( wy) * ((1.0f - wx) * im.at<float>(y+1,x) + wx * im.at<float>(y+1,x+1));
} else {
*out++ = 0;
ret = true; // touching boundary of the input
}
}
}
return ret;
}
Can anybody please help to find an equivalent function in OpenCV for the code above? I'm not expert on image processing, so I don't really know what the fucntion above does in details, but I think this is a warp-affine transformation, even though I don't really know how to define an OpenCV equivalent.
It seems that the input images are the blurred image, the original image or small patches of it. The output result is always a small patch.
Here are some samples:
Sample 1:
Args:
ofx=175.497 ofsy=315.06 a11=1.69477 a12=0.0671724 a21=0.0679493 a22=1.56309
Input image:
Output image:
Sample 2:
Args:
ofx=572.121 ofsy=326.659 a11=0.871508 a12=0 a21=0.346405 a22=1.14744
Input image:
Output image:
Sample 3:
ofx=66.571 ofsy=148.991 a11=1.12027 a12=0.126609 a21=0.126609 a22=2.53436
Input image:
Output image:
These are different sections of the original code where the function is called:
// warp input according to current shape matrix
interpolate(wrapper.prevBlur, lx, ly, u11*ratio, u12*ratio, u21*ratio, u22*ratio, img);
Mat smoothed(patchImageSize, patchImageSize, CV_32FC1, (void *)&workspace.front());
// interpolate with det == 1
if (!interpolate(img, x, y, a11, a12, a21, a22, smoothed))
{
// subsample with corresponding scale
interpolate(smoothed, (float)(patchImageSize>>1), (float)(patchImageSize>>1), imageToPatchScale, 0, 0, imageToPatchScale, patch);
// ok, do the interpolation
interpolate(img, x, y, a11, a12, a21, a22, patch);
This is what happens when I try to use warpAffine in the following way:
// warp input according to current shape matrix
interpolate(wrapper.prevBlur, lx, ly, u11*ratio, u12*ratio, u21*ratio, u22*ratio, img);
Mat warp_mat( 2, 3, CV_32FC1 );
Mat myPatch(img.rows, img.cols, CV_32FC1);
warp_mat.at<float>(0,2) = lx;
warp_mat.at<float>(1,2) = ly;
warp_mat.at<float>(0,0) = u11*ratio;
warp_mat.at<float>(0,1) = u12*ratio;
warp_mat.at<float>(1,0) = u21*ratio;
warp_mat.at<float>(1,1) = u22*ratio;
warpAffine(wrapper.prevBlur, myPatch, warp_mat, myPatch.size());
The resulting myPatch matrix is a zero matrix, while img (obtained by interpolate) is:
[19.109245, 19.189388, 18.941183, 18.454611, 18.285404, 19.447983, 22.037096, 28.504759, 37.753605, 50.69936, 61.34388, 67.619637, 70.699326, 71.640556, 73.347702, 72.383781, 70.7649, 72.320709, 74.32235;
18.464636, 18.408369, 18.347059, 18.194805, 17.982847, 18.312258, 18.990305, 21.852564, 26.399525, 35.10569, 44.444019, 53.986103, 59.851856, 63.937149, 67.766968, 70.979973, 73.074722, 77.097763, 82.344398;
17.838448, 17.706562, 17.580456, 17.869242, 18.216852, 18.72654, 19.004158, 20.150208, 21.66539, 26.167187, 31.805283, 41.04277, 48.207466, 54.719109, 59.793156, 65.378006, 71.004974, 77.016037, 86.317352;
17.257101, 17.117496, 16.95055, 17.34347, 18.505379, 20.129673, 21.161978, 22.195414, 22.287436, 24.150574, 26.179817, 32.619934, 39.298115, 46.696926, 52.091522, 57.986988, 64.629898, 72.434052, 82.955505;
16.810595, 16.665813, 16.672272, 17.16098, 18.665346, 21.783976, 24.785789, 27.150511, 27.23918, 27.834826, 27.594404, 30.645121, 35.405987, 42.133587, 46.915634, 51.880707, 57.028702, 64.57579, 74.402069;
16.687065, 16.451401, 16.626608, 17.460049, 19.36956, 23.552647, 28.802736, 33.788773, 35.505379, 35.85894, 34.729523, 34.880505, 37.088661, 42.075432, 45.702, 49.056709, 51.509052, 56.637093, 63.660839;
16.802176, 16.594761, 16.863697, 18.126085, 20.491119, 25.517574, 32.737259, 40.572498, 45.324429, 46.528313, 45.586109, 44.153858, 43.667118, 46.450905, 48.539593, 50.182858, 50.18359, 51.575584, 54.267056;
17.036257, 17.025221, 17.271259, 18.925261, 22.124079, 27.620583, 35.921772, 46.177872, 54.232437, 57.583233, 57.648571, 55.857315, 53.885891, 54.148857, 55.00872, 54.9893, 52.946201, 50.873283, 49.034798;
17.337849, 17.61212, 18.028404, 19.572941, 23.455297, 29.841951, 38.668663, 49.819805, 60.617371, 66.327873, 68.025574, 66.935631, 64.995117, 63.513988, 63.28405, 62.325748, 58.940784, 53.796066, 48.033508;
17.798275, 18.203262, 19.018663, 20.718761, 24.611408, 31.378065, 40.706932, 51.637016, 63.323963, 71.373169, 74.578476, 74.412659, 74.106857, 72.411026, 71.710922, 70.007111, 66.181709, 58.721882, 50.149853;
18.593805, 19.017687, 20.172789, 22.093014, 25.971659, 32.813194, 41.989246, 52.252911, 62.929924, 71.418938, 76.355003, 77.044289, 78.709656, 78.83432, 78.581551, 76.614075, 72.71788, 63.598377, 52.698578;
19.567734, 20.197411, 21.640959, 24.039509, 27.603041, 34.091061, 42.821777, 52.127884, 61.030842, 68.610733, 73.860558, 75.530617, 78.25412, 81.30085, 82.840904, 80.822067, 76.685196, 67.430412, 54.54921;
21.115396, 21.835562, 23.40497, 26.244884, 30.036913, 35.568745, 43.308716, 51.656746, 58.69318, 64.595673, 69.845467, 72.11985, 74.878944, 79.890228, 83.964821, 82.866249, 77.71666, 68.196243, 55.256557;
23.264105, 24.024746, 25.705564, 28.513554, 32.514004, 37.26601, 43.47644, 50.611153, 56.786697, 61.13575, 66.052094, 69.762238, 71.692001, 76.810669, 81.848129, 82.157066, 76.844963, 66.500725, 54.042095;
26.102678, 26.758638, 28.201065, 30.806498, 34.584103, 38.752495, 43.416939, 48.890656, 54.433743, 58.482693, 63.515507, 69.373245, 71.917755, 74.965172, 78.791039, 79.034378, 73.354454, 62.917992, 50.983219;
29.008026, 30.016344, 30.787025, 32.692429, 35.850079, 39.365425, 42.956245, 46.993965, 51.688225, 56.120068, 61.624519, 69.804024, 74.923134, 76.170395, 76.252747, 74.715118, 68.599701, 58.000847, 47.082359;
31.630077, 33.315144, 33.247631, 33.903202, 36.094364, 38.939133, 42.000217, 45.338474, 49.197887, 53.639317, 59.658398, 69.140472, 77.870468, 79.725624, 75.932251, 69.885872, 62.522583, 52.486378, 42.571148;
34.113537, 36.435402, 35.544792, 34.225368, 35.189747, 37.445477, 40.579632, 44.427345, 48.191299, 52.085419, 57.660496, 66.887024, 77.807755, 81.70005, 76.676743, 66.486168, 56.192219, 46.825108, 38.276539;
37.42725, 39.82682, 37.698589, 34.016525, 33.155304, 35.16758, 39.039139, 44.336964, 49.359722, 52.590809, 56.610603, 64.08419, 74.419289, 80.603294, 76.006302, 63.653465, 50.843102, 41.247444, 34.471062]
Update after comment:
These are results by using [[1, 0, 0], [0, 1, 0]] with the following code:
Mat warp_mat( 2, 3, CV_32FC1 );
Mat myPatch(img.rows, img.cols, CV_32FC1);
warp_mat.at<float>(0,0) = 1; //u11*ratio
warp_mat.at<float>(0,1) = 0; //u12*ratio
warp_mat.at<float>(0,2) = 0+(img.cols >> 1); //lx
warp_mat.at<float>(1,0) = 0; //u21*ratio
warp_mat.at<float>(1,1) = 1; //u22*ratio
warp_mat.at<float>(1,2) = 0+(img.rows >> 1); //ly
warpAffine(wrapper.prevBlur, myPatch, warp_mat, myPatch.size());
interpolate(wrapper.prevBlur, 0, 0, 1, 0, 0, 1, img);
std::cout<<"img="<<std::endl<<img<<std::endl;
std::cout<<"myPatch="<<std::endl<<myPatch<<std::endl;
The result is the same, but if I try to use:
warp_mat.at<float>(0,0) = 1; //u11*ratio
warp_mat.at<float>(0,1) = 1; //u12*ratio
warp_mat.at<float>(0,2) = 0+(img.cols >> 1); //lx
warp_mat.at<float>(1,0) = 0; //u21*ratio
warp_mat.at<float>(1,1) = 1; //u22*ratio
warp_mat.at<float>(1,2) = 0+(img.rows >> 1); //ly
warpAffine(wrapper.prevBlur, myPatch, warp_mat, myPatch.size());
interpolate(wrapper.prevBlur, 0, 0, 1, 1, 0, 1, img);
The matrix are "mirrored":
myPatch=
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 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.4431293, 2.1086276, 1.7749974, 1.5721301, 1.5403291, 1.6410155, 1.8406107, 2.1113796, 2.3246853, 2.274801;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3276107, 2.0702307, 1.8100098, 1.6615094, 1.6572961, 1.7410251, 1.8701531, 2.0462515, 2.1933937;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3676813, 2.1666555, 1.9666147, 1.8710723, 1.9005303, 1.9753534, 2.0355756, 2.1005828;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.4378726, 2.2967758, 2.1802788, 2.1628339, 2.2288194, 2.2786529, 2.2584724;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3656359, 2.3085568, 2.3188434, 2.4140301, 2.513881, 2.5077794;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.206573, 2.20857, 2.3185263, 2.5056028, 2.6312659;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.1686711, 2.1401191, 2.2343175, 2.4260342;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3495517, 2.2178252, 2.1930335;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.6443374, 2.4216607;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.8480706]
img=
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 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.4431293, 2.1086276, 1.7749974, 1.5721301, 1.5403291, 1.6410155, 1.8406107, 2.1113796, 2.3246853, 2.274801;
0, 0, 0, 0, 0, 0, 0, 0, 2.3276107, 2.0702307, 1.8100098, 1.6615094, 1.6572961, 1.7410251, 1.8701531, 2.0462515, 2.1933937, 2.1447542, 1.8548106;
0, 0, 0, 0, 0, 0, 0, 2.3676813, 2.1666555, 1.9666147, 1.8710723, 1.9005303, 1.9753534, 2.0355756, 2.1005828, 2.1541297, 2.0949042, 1.8804716, 1.6108752;
0, 0, 0, 0, 0, 0, 2.4378726, 2.2967758, 2.1802788, 2.1628339, 2.2288194, 2.2786529, 2.2584724, 2.2164674, 2.1899939, 2.1344388, 2.0028977, 1.8055484, 1.6097167;
0, 0, 0, 0, 0, 2.3656359, 2.3085568, 2.3188434, 2.4140301, 2.513881, 2.5077794, 2.3889487, 2.2654738, 2.21731, 2.2129889, 2.1711345, 2.027447, 1.7903067, 1.5879864;
0, 0, 0, 0, 2.206573, 2.20857, 2.3185263, 2.5056028, 2.6312659, 2.5770819, 2.3866575, 2.2314539, 2.2230167, 2.3092971, 2.3504019, 2.2321868, 1.9485472, 1.637617, 1.494508;
0, 0, 0, 2.1686711, 2.1401191, 2.2343175, 2.4260342, 2.566293, 2.5228219, 2.3388758, 2.2057574, 2.2558136, 2.4211838, 2.5120842, 2.3888607, 2.0588915, 1.6645602, 1.4044838, 1.4204007;
0, 0, 2.3495517, 2.2178252, 2.1930335, 2.3035395, 2.4375367, 2.446404, 2.3236551, 2.2328601, 2.3145993, 2.5046468, 2.5949829, 2.4436085, 2.0789487, 1.6472976, 1.3386253, 1.3225981, 1.6233296;
0, 2.6443374, 2.4216607, 2.271126, 2.2733064, 2.367074, 2.4035037, 2.3307135, 2.2715025, 2.3534446, 2.5142543, 2.558598, 2.3710468, 2.0039113, 1.6069642, 1.3526549, 1.3859948, 1.7268054, 2.1843567;
2.8480706, 2.6081781, 2.4022317, 2.3262172, 2.3576505, 2.3759208, 2.3233094, 2.2885542, 2.3600159, 2.4632583, 2.4390275, 2.2265964, 1.9053584, 1.6181513, 1.4964664, 1.6123655, 1.9332824, 2.2962041, 2.4815767]
And finally using:
warp_mat.at<float>(0,0) = 0; //u11*ratio
warp_mat.at<float>(0,1) = 1; //u22*ratio
warp_mat.at<float>(0,2) = 0+(img.cols >> 1); //lx
warp_mat.at<float>(1,0) = 1; //u21*ratio
warp_mat.at<float>(1,1) = 1; //u22*ratio
warp_mat.at<float>(1,2) = 0+(img.rows >> 1); //ly
I get:
myPatch=
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 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.4431293, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.1086276, 2.3276107, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.7749974, 2.0702307, 2.3676813, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.5721301, 1.8100098, 2.1666555, 2.4378726, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.5403291, 1.6615094, 1.9666147, 2.2967758, 2.3656359, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.6410155, 1.6572961, 1.8710723, 2.1802788, 2.3085568, 2.206573, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.8406107, 1.7410251, 1.9005303, 2.1628339, 2.3188434, 2.20857, 2.1686711, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.1113796, 1.8701531, 1.9753534, 2.2288194, 2.4140301, 2.3185263, 2.1401191, 2.3495517, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3246853, 2.0462515, 2.0355756, 2.2786529, 2.513881, 2.5056028, 2.2343175, 2.2178252, 2.6443374, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.274801, 2.1933937, 2.1005828, 2.2584724, 2.5077794, 2.6312659, 2.4260342, 2.1930335, 2.4216607, 2.8480706]
img=
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 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.4431293, 2.3276107, 2.3676813, 2.4378726, 2.3656359, 2.206573, 2.1686711, 2.3495517, 2.6443374, 2.8480706;
0, 0, 0, 0, 0, 0, 0, 0, 2.1086276, 2.0702307, 2.1666555, 2.2967758, 2.3085568, 2.20857, 2.1401191, 2.2178252, 2.4216607, 2.6081781, 2.6495261;
0, 0, 0, 0, 0, 0, 0, 1.7749974, 1.8100098, 1.9666147, 2.1802788, 2.3188434, 2.3185263, 2.2343175, 2.1930335, 2.271126, 2.4022317, 2.4685297, 2.4485474;
0, 0, 0, 0, 0, 0, 1.5721301, 1.6615094, 1.8710723, 2.1628339, 2.4140301, 2.5056028, 2.4260342, 2.3035395, 2.2733064, 2.3262172, 2.3705757, 2.3652363, 2.3247712;
0, 0, 0, 0, 0, 1.5403291, 1.6572961, 1.9005303, 2.2288194, 2.513881, 2.6312659, 2.566293, 2.4375367, 2.367074, 2.3576505, 2.3551981, 2.3311026, 2.2715149, 2.1814501;
0, 0, 0, 0, 1.6410155, 1.7410251, 1.9753534, 2.2786529, 2.5077794, 2.5770819, 2.5228219, 2.446404, 2.4035037, 2.3759208, 2.3474753, 2.3124287, 2.240618, 2.1282687, 2.0381868;
0, 0, 0, 1.8406107, 1.8701531, 2.0355756, 2.2584724, 2.3889487, 2.3866575, 2.3388758, 2.3236551, 2.3307135, 2.3233094, 2.3084226, 2.2854021, 2.2117574, 2.088321, 1.9926676, 1.9839712;
0, 0, 2.1113796, 2.0462515, 2.1005828, 2.2164674, 2.2654738, 2.2314539, 2.2057574, 2.2328601, 2.2715025, 2.2885542, 2.2938819, 2.2722201, 2.1820612, 2.0477793, 1.957217, 1.954851, 2.0058911;
0, 2.3246853, 2.1933937, 2.1541297, 2.1899939, 2.21731, 2.2230167, 2.2558136, 2.3145993, 2.3534446, 2.3600159, 2.3450513, 2.2874477, 2.1686828, 2.0435023, 1.9943975, 2.0270162, 2.0777535, 2.1049571;
2.274801, 2.1447542, 2.0949042, 2.1344388, 2.2129889, 2.3092971, 2.4211838, 2.5046468, 2.5142543, 2.4632583, 2.3841665, 2.2811179, 2.1669631, 2.1026075, 2.1358697, 2.2212756, 2.2625117, 2.2268343, 2.180846]
I think you basically answered yourself and it looks like a basic affine transformation.
The equivelent in OpenCV is warpAffine.
In the flags of the function you can give it any of the InterpolationFlags.
The transformation matrix M at your case will be:
[[a11, a12, ofsx],
[a21, a22, ofsy]
The output size is also a parameter, dependes on your numbers.
And if you want to optimize it as you say, you can compile OpenCV with CUDA support and then you could use the GPU version of this function.
I have a bunch of blocks that needs to be drawn into a grid. Now displaying them unscaled everything is fine but when I try to scale them down to fit withing a window I get "scale-artifacts" because I use a normal scale-ratio formula and floats.
Is there a way to avoid these problems ?
Common example data:
Original length: 200000
Scaled down to a 25x25 pixel grid (it's this small for development and debugging)
The scaled down max length: 625 (25 * 25)
Scale-ratio: (625 / 200000) = 0,003125
Example data 1 - overlapping, scaled blocks overwrite each other
Start of block => end of block: [start, end)
1: 2100 => 2800
2: 2800 => 3600
3: 3600 => 4500
4: 4500 => 5500
Jumping over showing the output of this example because I think example 2 and 3 will get the point across. Left it in for completeness.
Example data 2 - incorrect space between 2 and 3
Start of block => end of block: [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:
pixel start, end, length
1: 3, 0, 1
2: 4, 0, 1
3: 6, 0, 1
Displayed grid:
[ 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 ]
...
Example data 3 - 1 moved a step back incorrectly
Start of block => end of block: [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:
pixel start, end, length
1: 2, 0, 1
2: 4, 0, 1
3: 5, 0, 1
Displayed grid:
[ 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 ]
...
What example data 2 and 3 should have looked like:
[ 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 ]
...
Remember the block values are [start, end)
Preemptive strike (down-voters / trollers) Remember: I'm not psychic or a mind-reader. If you want to give negative do it in a constrictive way or it is useless (i will not learn anything) and will just pollute the thread.
Update
#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;
}
Output:
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 ]
This code example demonstrates my problem more clearly.
Interesting fact: mingw-g++, which i used to write this example, shows slightly different values. I usually use visual studio 2010 but couldn't this time because I'm not at home.
I am not sure if I am getting the problem statement but I will take a stab at it. You have ranges of information that you are displaying contigously a range is usually [a,b). Everything is fine when a and b directly represent the pixels that you are trying to draw, but you are having problems when you want to scale the whole thing.
Not dealing with multiple rows of pixels, if you have two ranges R1=[a,b) and R2=[b,c) unscaled you just draw from a to b-1 and from b to c-1 and your ranges are drawn so what is the problem in the scaled case drawing from (int)(a*scale) to ((int)(b*scale)-1) and then from (int)(b*scale) to ((int)(c*scale)-1), you can use any float to int conversion, rounding, floor or ceiling and you should be ok.
The next problem area would be if your scale ranges amount to less than 1 pixel, in this case you might need to detect if the size of the scaled range is 0 and carry a correction factor (in pixels) that is added at the end of the calculation.
Pseudocode
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);
}
This will eventually fail if you have more Ranges than blocks in your scaled down grid, you would have to figure out how to drop ranges completely. In draw rang you map your index to an actual block coordinate.
Does this solve your problem ?
Yeah +1 to get you back up, the question is OK.
I don't know why people thing it is so fun to downvote without even leaving a comment.
Well, to the question :-)
Usually when drawing you have this overlapping issues and in 3D computer graphics with scanline renderers (DirectX & OpenGL for ex) they usually Skip exactly one pixel (say all on the right and down side).
Maybe this can help you out.
It is possible too that when the division is perfect, you don't have the artefacts so you must maybe deal with that (ie. if the value is a 'perfect integer', for example 185.000000 then don't remove the last pixel).
HTH