我試圖優化非常大的圖像的旋轉中心任意角度,最小的是4096×4096或〜1600萬像素。優化旋轉矩陣 - 關於矩陣
旋轉總是關於圖像的中心和圖像不一定總是正方形的,但永遠是2
我有機會獲得MKL/TBB,其中MKL是一個優化的BLAS我的目標動力平臺。我不熟悉這個操作是否在BLAS中。所以,裸露在我面前的答案是顯而易見的,只是我不熟悉的BLAS功能。
我盡了最大努力,到目前爲止都是圍繞17-25ms爲4096×4096的圖像(相同的圖像尺寸,這意味着我可能踩遍緩存很不一致)。矩陣是16字節對齊的。現在
,目標不能調整大小。所以,裁剪應該會發生。例如,以45度角旋轉的矩形矩陣必定會夾在角上,該位置的值應爲零。
現在,我盡了最大努力用瓷磚的做法 - 不優雅是尚未被放入片大小也不循環展開。
這裏是我的算法,因爲它代表利用TBB - http://threadingbuildingblocks.org/:
//- cosa = cos of the angle
//- sina = sin of angle
//- for those unfamiliar with TBB, this is giving me blocks of rows or cols that
//- are unique per thread
void operator() (const tbb::blocked_range2d<size_t, size_t> r) const
{
double xOffset;
double yOffset;
int lineOffset;
int srcX;
int srcY;
for (size_t row = r.rows().begin(); row != r.rows().end(); ++row)
{
const size_t colBegin = r.cols().begin();
xOffset = -(row * sina) + xHelper + (cosa * colBegin);
yOffset = (row * cosa) + yHelper + (sina * colBegin);
lineOffset = (row * rowSpan); //- all col values are offsets of this row
for(size_t col = colBegin; col != r.cols().end(); ++col, xOffset += cosa, yOffset += sina)
{
srcX = xOffset;
srcY = yOffset;
if(srcX >= 0 && srcX < colSpan && srcY >= 0 && srcY < rowSpan)
{
destData[col + lineOffset] = srcData[srcX + (srcY * rowSpan)];
}
}
}
}
我對這個函數的調用是這樣的:
double sina = sin(angle);
double cosa = cos(angle);
double centerX = (colSpan)/2;
double centerY = (rowSpan)/2;
//- Adding .5 for rounding
const double xHelper = centerX - (centerX * cosa) + (centerY * sina) + .5;
const double yHelper = centerY - (centerX * sina) - (centerY * cosa) + .5;
tbb::parallel_for(tbb::blocked_range2d<size_t, size_t>(0, rowSpan, 0, colSpan), DoRotate(sina, cosa, xHelper, yHelper, rowSpan, colSpan, (fcomplex *)pDestData, (fcomplex *)pSrcData));
浮點型複數僅僅是在複數的房子表示。它被定義爲:
struct fcomplex
{
float real;
float imag;
};
所以,我想要做複數值矩陣的繞它的中心在任意角度非常大的圖像儘可能快。
更新:
基於奇妙的反饋,我已經更新到這一點:這是增加約40%。我想知道,但如果什麼都可以做:
void operator() (const tbb::blocked_range2d<size_t, size_t> r) const
{
float xOffset;
float yOffset;
int lineOffset;
__m128i srcXints;
__m128i srcYints;
__m128 dupXOffset;
__m128 dupYOffset;
for (size_t row = r.rows().begin(); row != r.rows().end(); ++row)
{
const size_t colBegin = r.cols().begin();
xOffset = -(row * sina) + xHelper + (cosa * colBegin);
yOffset = (row * cosa) + yHelper + (sina * colBegin);
lineOffset = (row * rowSpan); //- all col values are offsets of this row
for(size_t col = colBegin; col != r.cols().end(); col+=4, xOffset += dupOffsetsX.m128_f32[3], yOffset += dupOffsetsY.m128_f32[3])
{
dupXOffset = _mm_load1_ps(&xOffset); //- duplicate the x offset 4 times into a 4 float field
dupYOffset = _mm_load1_ps(&yOffset); //- duplicate the y offset 4 times into a 4 float field
srcXints = _mm_cvtps_epi32(_mm_add_ps(dupOffsetsX, dupXOffset));
srcYints = _mm_cvtps_epi32(_mm_add_ps(dupOffsetsY, dupYOffset));
if(srcXints.m128i_i32[0] >= 0 && srcXints.m128i_i32[0] < colSpan && srcYints.m128i_i32[0] >= 0 && srcYints.m128i_i32[0] < rowSpan)
{
destData[col + lineOffset] = srcData[srcXints.m128i_i32[0] + (srcYints.m128i_i32[0] * rowSpan)];
}
if(srcXints.m128i_i32[1] >= 0 && srcXints.m128i_i32[1] < colSpan && srcYints.m128i_i32[1] >= 0 && srcYints.m128i_i32[1] < rowSpan)
{
destData[col + 1 + lineOffset] = srcData[srcXints.m128i_i32[1] + (srcYints.m128i_i32[1] * rowSpan)];
}
if(srcXints.m128i_i32[2] >= 0 && srcXints.m128i_i32[2] < colSpan && srcYints.m128i_i32[2] >= 0 && srcYints.m128i_i32[2] < rowSpan)
{
destData[col + 2 + lineOffset] = srcData[srcXints.m128i_i32[2] + (srcYints.m128i_i32[2] * rowSpan)];
}
if(srcXints.m128i_i32[3] >= 0 && srcXints.m128i_i32[3] < colSpan && srcYints.m128i_i32[3] >= 0 && srcYints.m128i_i32[3] < rowSpan)
{
destData[col + 3 + lineOffset] = srcData[srcXints.m128i_i32[3] + (srcYints.m128i_i32[3] * rowSpan)];
}
}
}
}
更新2: 我把下面的解決方案,同時考慮到建議我得到的答案以及旋轉矩形時修復bug。
I [編輯了雜波](http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be-removed-from-posts)一個第二時間。 – Bart
這爲GPU計算而尖叫。也許這對你來說是一種選擇。 –
我記得在人傑地靈使用[布氏算法(http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm),以避免浮點運算在這樣的背景下。這可能是一個想法,因爲您的xOffset和yOffset修改似乎是Bresenham的理想選擇。 –