Affine transformation

Affine transformation, also known as affine mapping, is the transformation of a vector space into another vector space by a linear transformation followed by a translation in geometry. Affine transformation can maintain the “flatness” of the image, including rotation, scaling, translation, and tangent operation. Generally speaking, if the affine transformation matrix is 23, the elements in the third column play the role of translation, the first two columns are scaled on the diagonal, and the rest are rotated or miscut. Affine transformation is a linear transformation from two dimensional coordinates (x, y) to two dimensional coordinates (u, v). The mathematical expression is as follows:

The corresponding homogeneous coordinate system is as follows

Affine transformation preserves the “flatness” and “parallelism” of a two-dimensional graph (a straight line is still a straight line after affine transformation) (the relative position relation between lines remains unchanged, parallel lines are still parallel after affine transformation, and the position order of points on the line does not change). The three noncollinear pairs of corresponding points determine a unique affine transformation.



API

Compute the rotation matrix

public static Mat getRotationMatrix2D(Point center, double angle, double scale) 

Copy the code
  • Parameter 1: Center, the central position of image rotation
  • Parameter 2: Angle, the Angle of image rotation, in degrees, and the positive value is counterclockwise rotation
  • Parameter 3: scale, the scale factor of two axes, can realize image scaling in the rotation process, without scaling input 1

The generated rotation matrix is related to rotation Angle and rotation center.


For example, if scale is 2 and Angle is 90 degrees, m1 is the rotation matrix


Calculate affine matrix (three points)

public static Mat getAffineTransform(MatOfPoint2f src, MatOfPoint2f dst)

Copy the code
  • Parameter 1: SRC, three pixel coordinates in the original image
  • Parameter two: DST, three pixel coordinates in the target image
  • Return value: 2*3 transformation matrix. Perspective transformation is a 3 by 3 matrix, affine is a 2 by 3 matrix

Affine transformation

public static void warpAffine(Mat src, Mat dst, Mat M, Size dsize, int flags, int borderMode, Scalar borderValue) 

Copy the code
  • Parameter 1: SRC, original image

  • Parameter 2: DST, output image after perspective transformation, same data type as SRC, but same size as Dsize

  • Parameter 3: M, 2*3 transformation matrix

  • Parameter 4: Dsize, output image size

  • Parameter 5: flags, interpolation method 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;

    Copy the code
  • Parameter 6: borderMode, the flag of the pixel boundary extrapolation method. BORDER_CONSTANT or BORDER_REPLICATE

Boundary fill value role
BORDER_CONSTANT 0 Filled with specific values, such as iiiiii | abcdefgh | iiiiiii
BORDER_REPLICATE 1 Replication fill on both ends, such as aaaaaa | abcdefgh | HHHHHHH
BORDER_REFLECT 2 Flashback filling, such as fedcba | abcdefgh | hgfedcb
BORDER_WRAP 3 Positive sequence filling, such as cdefgh | abcdefgh | abcdefg
BORDER_REFLECT_101 4 Does not contain boundary value flashbacks filling, gfedcb | abcdefgh | gfedcba
BORDER_TRANSPARENT 5 Random fill, uvwxyz | abcdefgh | ijklmno
BORDER_REFLECT101 4 The same as the BORDER_REFLECT_101
BORDER_DEFAULT 4 The same as the BORDER_REFLECT_101
BORDER_ISOLATED 16 Don’t care about what’s outside the area of interest
  • Parameter seven: borderValue, the number used to fill the border, 0 by default

operation

class AffineActivity : AppCompatActivity() {



private lateinit var mBinding: ActivityAffineBinding

private lateinit var mRgb: Mat



override fun onCreate(savedInstanceState: Bundle?). {

super.onCreate(savedInstanceState)

mBinding = DataBindingUtil.setContentView(this, R.layout.activity_affine)

mRgb = Mat()

val bgr = Utils.loadResource(this, R.drawable.lena)

Imgproc.cvtColor(bgr, mRgb, Imgproc.COLOR_BGR2RGB)

bgr.release()

showMat(mBinding.ivLena, mRgb)

}





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)

}



private fun rotateMatrix(degree: Double, scale: Double) {

val center = Point(mRgb.width() / 2.0, mRgb.height() / 2.0)

val matrix = Imgproc.getRotationMatrix2D(center, degree, scale)

val size = mRgb.size()

val dst = Mat()

Imgproc.warpAffine(mRgb, dst, matrix, size)

showMat(mBinding.ivResult, dst)

dst.release()

}



private fun threePointsMatrix(a) {

val srcPoints = arrayOfNulls<Point>(3)

val dstPoints = arrayOfNulls<Point>(3)



srcPoints[0] = Point(0.0.0.0)

srcPoints[1] = Point(0.0, mRgb.width() - 1.0)

srcPoints[2] = Point(mRgb.height() - 1.0, mRgb.width() - 1.0)



dstPoints[0] = Point(mRgb.width() * 0.11, mRgb.width() * 0.2)

dstPoints[1] = Point(mRgb.width() * 0.15, mRgb.width() * 0.7)

dstPoints[2] = Point(mRgb.width() * 0.81, mRgb.width() * 0.85)



val transform = Imgproc.getAffineTransform(

MatOfPoint2f(srcPoints[0], srcPoints[1], srcPoints[2]),

MatOfPoint2f(dstPoints[0], dstPoints[1], dstPoints[2])

)

val dst = Mat()

val size = mRgb.size()

Imgproc.warpAffine(mRgb, dst, transform, size)

showMat(mBinding.ivResult, dst)

dst.release()

}





override fun onCreateOptionsMenu(menu: Menu?).: Boolean {

menuInflater.inflate(R.menu.menu_affine, menu)

return true

}



override fun onOptionsItemSelected(item: MenuItem): Boolean {

title = item.title

when (item.itemId) {

R.id.affine_rotate_scale -> rotateMatrix(120.0.1.2)

R.id.affine_three_points -> threePointsMatrix()

}

return true

}

}

Copy the code

The effect

Take the rotation matrix to complete affine
Affine is completed by taking the matrix of three points

The source code

Github.com/onlyloveyd/…


This article is formatted using MDNICE