Android OpenCV(十二):极坐标变换

极坐标

极坐标系(polar coordinates)是指在平面内由极点、极轴和极径组成的坐标系。在平面上取定一点O,称为极点。从O出发引一条射线Ox,称为极轴。再取定一个单位长度,通常规定角度取逆时针方向为正。这样,平面上任一点P的位置就可以用线段OP的长度ρ以及从Ox到OP的角度θ来确定,有序数对(ρ,θ)就称为P点的极坐标,记为P(ρ,θ);ρ称为P点的极径,θ称为P点的极角。

极坐标和笛卡尔坐标的转换关系:

x = ρcosθ

y = ρsinθ

反过来也可以用过x, y 计算出ρ,θ的值

API

public static void warpPolar(Mat src, Mat dst, Size dsize, Point center, double maxRadius, int flags)
  • 参数一:src,原图像,可以是灰度图像或者彩色图像。

  • 参数二:dst,极坐标变换后输出图像,与原图像具有相同的数据类型和通道数。

  • 参数三:dsize,目标图像大小。

  • 参数四:center,极坐标变换时极坐标的原点坐标。

  • 参数五:maxRadius,变换时边界圆的半径,它也决定了逆变换时的比例参数。

  • 参数六:flags, 插值方法与极坐标映射方法标志,插值方法和极坐标映射方法如下,两个方法之间通过“+”或者“|”号进行连接。

    // C++: enum InterpolationFlags
    public static final int
            INTER_NEAREST = 0,
            INTER_LINEAR = 1,
            INTER_CUBIC = 2,
            INTER_AREA = 3,
            INTER_LANCZOS4 = 4,
            INTER_LINEAR_EXACT = 5,
            INTER_MAX = 7,
            WARP_FILL_OUTLIERS = 8,
            WARP_INVERSE_MAP = 16;//逆变换
    
    // C++: enum WarpPolarMode
    public static final int
            WARP_POLAR_LINEAR = 0,//极坐标变换
            WARP_POLAR_LOG = 256;//半对数极坐标变换
    

操作

class PolarActivity : AppCompatActivity() {

    private lateinit var mBinding: ActivityPolarBinding
    private lateinit var mRgb: Mat
    private lateinit var mPolar: Mat

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_polar)

        val bgr = Utils.loadResource(this, R.drawable.circle)
        mRgb = Mat()
        Imgproc.cvtColor(bgr, mRgb, Imgproc.COLOR_BGR2RGB)
        showMat(mBinding.ivCircle, mRgb)
        bgr.release()
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_polar, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.polar -> {
                polarTransform(mRgb)
            }

            R.id.reverse_polar -> {
                if (!this::mPolar.isInitialized) {
                    Toast.makeText(this, "请先进行极坐标变换", Toast.LENGTH_SHORT).show()
                } else {
                    reversePolarTransform(mPolar)
                }
            }
        }
        return true
    }

    private fun polarTransform(source: Mat) {
        val center = Point(source.width() / 2.0, source.height() / 2.0)
        mPolar = Mat()
        val size = mRgb.size()
        Imgproc.warpPolar(
            source,
            mPolar,
            size,
            center,
            center.x,
            Imgproc.INTER_LINEAR + Imgproc.WARP_POLAR_LINEAR
        )
        showMat(mBinding.ivResult, mPolar)
    }

    private fun reversePolarTransform(source: Mat) {
        val center = Point(source.width() / 2.0, source.height() / 2.0)
        val dst = Mat()
        val size = mRgb.size()
        Imgproc.warpPolar(
            source,
            dst,
            size,
            center,
            center.x,
            Imgproc.INTER_LINEAR + Imgproc.WARP_INVERSE_MAP
        )
        showMat(mBinding.ivResult, dst)
    }


    private fun showMat(view: ImageView, source: Mat) {
        val bitmap = Bitmap.createBitmap(source.width(), source.height(), Bitmap.Config.ARGB_8888)
        Utils.matToBitmap(source, bitmap)
        view.setImageBitmap(bitmap)
    }

    override fun onDestroy() {
        mRgb.release()
        mPolar.release()
        super.onDestroy()
    }
}

效果

极坐标变换

源码

https://github.com/onlyloveyd/LearningAndroidOpenCV

onlyloveyd CSDN认证博客专家 Android Kotlin OpenCV
个人公众号【OpenCV or Android】,热爱Android、Kotlin、Flutter和OpenCV。毕业于华中科技大学计算机专业,曾就职于华为武汉研究所。目前在三线小城市生活,专注Android、OpenCV、Kotlin、Flutter等有趣的技术。
已标记关键词 清除标记
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; } bool cartesian_to_polar(cv::Mat& mat_c, cv::Mat& mat_p, int img_d) { int color_num = mat_c.channels(); cout << "color_num=" << color_num << endl; mat_p = cv::Mat::zeros(img_d, img_d, CV_8UC1); //mat_p = cv::Mat::zeros(img_d, img_d, CV_8UC3); //mat_p = cv::Mat::zeros(img_d, img_d, color_num); 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); /* mat_p.ptr<Vec3b>(i, j)[0] = interpolate_bilinear(mat_c, ri, rf, rc, ti, tf, tc); mat_p.ptr<Vec3b>(i, j)[1] = interpolate_bilinear(mat_c, ri, rf, rc, ti, tf, tc); mat_p.ptr<Vec3b>(i, j)[2] = interpolate_bilinear(mat_c, ri, rf, rc, ti, tf, tc); */ } } } return true; }
©️2020 CSDN 皮肤主题: 博客之星2020 设计师:CY__ 返回首页