【算法+OpenCV】图像极坐标变换及基于OpenCV的实现
在醫學圖像處理,尤其是在處理血管斷層掃描類(如OCT、IVUS等)圖像的過程中,不可避免的會使用到極坐標變換,也即是我們通常所說的“方轉圓”。同樣,我們可以使用極坐標變換的反變換實現“圓轉方”
極坐標變換及其反變換的關鍵在于,根據極坐標變換前的圖像(我們稱為“方圖”)確定極坐標變換后的圖像(我們稱為“圓圖”)上每個像素點的像素值。也即是找到“圓圖”和“方圖”間幾何坐標的對應關系。
1、極坐標變換(方轉圓)
原理:如下圖所示,實現極坐標變換的關鍵即在于找到圓圖上任一點P(i,j),在方圖上對應的點p(m,n),然后通過插值算法實現圓圖上所有像素點的賦值。
方圖上,其行列數分別為M、N,方圖上的每一列對應為圓圖上的每條半徑,半徑方向存在著一個長度縮放因子delta_r = M/R,圓周方向被分為N等分,即角度因子為delta_t = 2π/N;
圓圖上,圖像坐標(i,j)和世界坐標(x,y)有著如下變換關系:x = j - R, y = R - i;
那么,圖中P點半徑長度為r = sqrt(x*x + y*y),角度theta = arctan(y/x);
圓圖上點P在方圖上對應行數為r/delta_r;
圓圖上點P在方圖上對應的列數n = thata/delta_t。
以上就是極坐標變換的基本原理,結合相應的插值算法,即可實現圖像的極坐標變換。
實現代碼如下:
bool cartesian_to_polar(cv::Mat& mat_c, cv::Mat& mat_p, int img_d) {mat_p = cv::Mat::zeros(img_d, img_d, CV_8UC1);int line_len = mat_c.rows;int line_num = mat_c.cols;double delta_r = (2.0*line_len) / (img_d - 1); //半徑因子double delta_t = 2.0 * PI / line_num; //角度因子double center_x = (img_d - 1) / 2.0;double center_y = (img_d - 1) / 2.0;for (int i = 0; i < img_d; i++){for (int j = 0; j < img_d; j++){double rx = j - center_x; //圖像坐標轉世界坐標double ry = center_y - i; //圖像坐標轉世界坐標double r = std::sqrt(rx*rx + ry*ry);if (r <= (img_d - 1) / 2.0){double ri = r * delta_r;int rf = (int)std::floor(ri);int rc = (int)std::ceil(ri);if (rf < 0){rf = 0;}if (rc > (line_len - 1)){rc = line_len - 1;}double t = std::atan2(ry, rx);if (t < 0){t = t + 2.0 * PI;}double ti = t / delta_t;int tf = (int)std::floor(ti);int tc = (int)std::ceil(ti);if (tf < 0){tf = 0;}if (tc > (line_num - 1)){tc = line_num - 1;}mat_p.ptr<uchar>(i)[j] = interpolate_bilinear(mat_c, ri, rf, rc, ti, tf, tc);}}}return true; }順便給一段雙線性插值的代碼:
uchar interpolate_bilinear(cv::Mat& mat_src, double ri, int rf, int rc, double ti, int tf, int tc) {double inter_value = 0.0;if (rf == rc && tc == tf){inter_value = mat_src.ptr<uchar>(rc)[tc];}else if (rf == rc){inter_value = (ti - tf) * mat_src.ptr<uchar>(rf)[tc] + (tc - ti) * mat_src.ptr<uchar>(rf)[tf];}else if (tf == tc){inter_value = (ri - rf) * mat_src.ptr<uchar>(rc)[tf] + (rc - ri) * mat_src.ptr<uchar>(rf)[tf];}else{double inter_r1 = (ti - tf) * mat_src.ptr<uchar>(rf)[tc] + (tc - ti) * mat_src.ptr<uchar>(rf)[tf];double inter_r2 = (ti - tf) * mat_src.ptr<uchar>(rc)[tc] + (tc - ti) * mat_src.ptr<uchar>(rc)[tf];inter_value = (ri - rf) * inter_r2 + (rc - ri) * inter_r1;}return (uchar)inter_value; }2、極坐標變換的反變換(圓轉方)
原理:顧名思義,極坐標變換的反變換即極坐標變換的逆變換,原理和極坐標變換類似,只是更為直接和方便,且不需要進行插值,這里就不再贅述了。
直接看代碼吧:
bool polar_to_cartesian(cv::Mat& mat_p, cv::Mat& mat_c, int rows_c, int cols_c) {mat_c = cv::Mat::zeros(rows_c, cols_c, CV_8UC1);int polar_d = mat_p.cols;double polar_r = polar_d / 2.0; // 圓圖半徑double delta_r = polar_r / rows_c; //半徑因子double delta_t = 2.0*PI / cols_c; //角度因子double center_polar_x = (polar_d - 1) / 2.0;double center_polar_y = (polar_d - 1) / 2.0;for (int i = 0; i < cols_c; i++){double theta_p = i * delta_t; //方圖第i列在圓圖對應線的角度double sin_theta = std::sin(theta_p);double cos_theta = std::cos(theta_p);for (int j = 0; j < rows_c; j++){double temp_r = j * delta_r; //方圖第j行在圓圖上對應的半徑長度int polar_x = (int)(center_polar_x + temp_r * cos_theta);int polar_y = (int)(center_polar_y - temp_r * sin_theta);mat_c.ptr<uchar>(j)[i] = mat_p.ptr<uchar>(polar_y)[polar_x];}}return true; }
3、結果
為驗證算法,下載了一張IVUS(血管超聲)圖像,先用極坐標反變換得到方圖,再用極坐標變換將方圖變換回圓圖,通過比較,變換前后的圖像基本一致,哦了~~~
原始圖
反極坐標變換圖
極坐標變換結果
2017.03.24完成初稿
總結
以上是生活随笔為你收集整理的【算法+OpenCV】图像极坐标变换及基于OpenCV的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【OpenCV3】cv::Mat中最值和
- 下一篇: 【OpenCV3】cv::Mat的定义与