├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── README.md ├── RR_Lib.cpp ├── RR_Lib.h ├── lena.jpg ├── main.cpp └── result.PNG /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | vs2015 3 | CMakeLists.txt.user 4 | 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: 2 | - cpp 3 | 4 | compiler: 5 | - gcc 6 | 7 | before_install: 8 | - sudo apt-get update 9 | 10 | install: 11 | 12 | # OpenCV v3.0.0 (beta) install code (modified from orignal source: https://github.com/jayrambhia/Install-OpenCV) 13 | 14 | # OpenCV dependencies - Details available at: http://docs.opencv.org/trunk/doc/tutorials/introduction/linux_install/linux_install.html 15 | - sudo apt-get install -y build-essential 16 | - sudo apt-get install -y cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev 17 | - sudo apt-get install -y python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev 18 | 19 | # Download v3.0.0 .zip file and extract. 20 | - curl -sL https://github.com/Itseez/opencv/archive/3.0.0-beta.zip > opencv.zip 21 | - unzip opencv.zip 22 | - cd opencv-3.0.0-beta 23 | 24 | # Create a new 'build' folder. 25 | - mkdir build 26 | - cd build 27 | 28 | # Set build instructions for Ubuntu distro. 29 | - cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=OFF -D WITH_V4L=ON -D INSTALL_C_EXAMPLES=OFF -D INSTALL_PYTHON_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D BUILD_EXAMPLES=OFF -D WITH_QT=OFF -D WITH_OPENGL=OFF .. 30 | 31 | # Run 'make' with four threads. 32 | - make -j4 33 | 34 | # Install to OS. 35 | - sudo make install 36 | 37 | # Add configuration to OpenCV to tell it where the library files are located on the file system (/usr/local/lib) 38 | - sudo sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf' 39 | 40 | - sudo ldconfig 41 | - echo "OpenCV installed." 42 | 43 | # We need to return to the repo "root" folder, so we can then 'cd' into the C++ project folder. 44 | - cd ../../ 45 | 46 | script: 47 | #- cd [project_dir] 48 | - cmake . 49 | - make 50 | #- ./cvRotatedRectLib -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Smorodov/RotatedRectLib/59911f8d91d5d43869bfe4eace8b0c155aba2128/CMakeLists.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Alt text](https://travis-ci.org/Smorodov/RotatedRectLib.svg?branch=master) 2 | # RotatedRectLib 3 | 4 | Small library for working with rotated rectangle shaped image regions. 5 | 6 | It allows manipulations with rotated rectangle image regions: 7 | 8 | 1) Extract rectangular rotated region. 9 | 10 | 2) Copy to rectangular rotated region. 11 | 12 | 3) Draw rotated rectangle. 13 | 14 | ![Alt text](result.PNG?raw=true "Result") -------------------------------------------------------------------------------- /RR_Lib.cpp: -------------------------------------------------------------------------------- 1 | #include "opencv2/opencv.hpp" 2 | #include "RR_Lib.h" 3 | 4 | using namespace std; 5 | using namespace cv; 6 | 7 | namespace RRLib { 8 | //---------------------------------------------- 9 | // Check if rotated box contained in image region 10 | //---------------------------------------------- 11 | bool boxInRange(cv::Mat& img, cv::RotatedRect& r) 12 | { 13 | Point2f rect_points[4]; 14 | r.points(rect_points); 15 | 16 | cv::Rect img_r = cv::Rect(0, 0, img.cols, img.rows); 17 | 18 | bool result = true; 19 | for (int i = 0; i < 4; ++i) 20 | { 21 | if (!img_r.contains(rect_points[i])) 22 | { 23 | result = false; 24 | break; 25 | } 26 | } 27 | return result; 28 | } 29 | //---------------------------------------------- 30 | // Check if rotated box contained in rectangular region 31 | //---------------------------------------------- 32 | bool boxInRange(cv::Rect r, cv::RotatedRect& rr) 33 | { 34 | Point2f rect_points[4]; 35 | rr.points(rect_points); 36 | bool result = true; 37 | for (int i = 0; i < 4; ++i) 38 | { 39 | if (!r.contains(rect_points[i])) 40 | { 41 | result = false; 42 | break; 43 | } 44 | } 45 | return result; 46 | } 47 | //---------------------------------------------- 48 | // Method from old OpenCV version 49 | //---------------------------------------------- 50 | void getQuadrangleSubPix_8u32f_CnR(const uchar* src, size_t src_step, cv::Size src_size, 51 | float* dst, size_t dst_step, Size win_size, 52 | const double *matrix, int cn) 53 | { 54 | int x, y, k; 55 | double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]; 56 | double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]; 57 | 58 | src_step /= sizeof(src[0]); 59 | dst_step /= sizeof(dst[0]); 60 | 61 | for (y = 0; y < win_size.height; y++, dst += dst_step) 62 | { 63 | double xs = A12 * y + A13; 64 | double ys = A22 * y + A23; 65 | double xe = A11 * (win_size.width - 1) + A12 * y + A13; 66 | double ye = A21 * (win_size.width - 1) + A22 * y + A23; 67 | 68 | if ((unsigned)(cvFloor(xs) - 1) < (unsigned)(src_size.width - 3) && 69 | (unsigned)(cvFloor(ys) - 1) < (unsigned)(src_size.height - 3) && 70 | (unsigned)(cvFloor(xe) - 1) < (unsigned)(src_size.width - 3) && 71 | (unsigned)(cvFloor(ye) - 1) < (unsigned)(src_size.height - 3)) 72 | { 73 | for (x = 0; x < win_size.width; x++) 74 | { 75 | int ixs = cvFloor(xs); 76 | int iys = cvFloor(ys); 77 | const uchar *ptr = src + src_step*iys; 78 | float a = (float)(xs - ixs), b = (float)(ys - iys), a1 = 1.f - a, b1 = 1.f - b; 79 | float w00 = a1*b1, w01 = a*b1, w10 = a1*b, w11 = a*b; 80 | xs += A11; 81 | ys += A21; 82 | 83 | if (cn == 1) 84 | { 85 | ptr += ixs; 86 | dst[x] = ptr[0] * w00 + ptr[1] * w01 + ptr[src_step] * w10 + ptr[src_step + 1] * w11; 87 | } 88 | else if (cn == 3) 89 | { 90 | ptr += ixs * 3; 91 | float t0 = ptr[0] * w00 + ptr[3] * w01 + ptr[src_step] * w10 + ptr[src_step + 3] * w11; 92 | float t1 = ptr[1] * w00 + ptr[4] * w01 + ptr[src_step + 1] * w10 + ptr[src_step + 4] * w11; 93 | float t2 = ptr[2] * w00 + ptr[5] * w01 + ptr[src_step + 2] * w10 + ptr[src_step + 5] * w11; 94 | 95 | dst[x * 3] = t0; 96 | dst[x * 3 + 1] = t1; 97 | dst[x * 3 + 2] = t2; 98 | } 99 | else 100 | { 101 | ptr += ixs*cn; 102 | for (k = 0; k < cn; k++) 103 | dst[x * cn + k] = ptr[k] * w00 + ptr[k + cn] * w01 + 104 | ptr[src_step + k] * w10 + ptr[src_step + k + cn] * w11; 105 | } 106 | } 107 | } 108 | else 109 | { 110 | for (x = 0; x < win_size.width; x++) 111 | { 112 | int ixs = cvFloor(xs), iys = cvFloor(ys); 113 | float a = (float)(xs - ixs), b = (float)(ys - iys), a1 = 1.f - a, b1 = 1.f - b; 114 | float w00 = a1*b1, w01 = a*b1, w10 = a1*b, w11 = a*b; 115 | const uchar *ptr0, *ptr1; 116 | xs += A11; 117 | ys += A21; 118 | 119 | if ((unsigned)iys < (unsigned)(src_size.height - 1)) 120 | ptr0 = src + src_step * iys, ptr1 = ptr0 + src_step; 121 | else 122 | ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height - 1) * src_step; 123 | 124 | if ((unsigned)ixs < (unsigned)(src_size.width - 1)) 125 | { 126 | ptr0 += ixs*cn; 127 | ptr1 += ixs*cn; 128 | for (k = 0; k < cn; k++) 129 | dst[x * cn + k] = ptr0[k] * w00 + ptr0[k + cn] * w01 + ptr1[k] * w10 + ptr1[k + cn] * w11; 130 | } 131 | else 132 | { 133 | ixs = ixs < 0 ? 0 : src_size.width - 1; 134 | ptr0 += ixs*cn; 135 | ptr1 += ixs*cn; 136 | for (k = 0; k < cn; k++) 137 | dst[x * cn + k] = ptr0[k] * b1 + ptr1[k] * b; 138 | } 139 | } 140 | } 141 | } 142 | } 143 | 144 | 145 | //---------------------------------------------- 146 | // Method from old OpenCV version 147 | //---------------------------------------------- 148 | 149 | void myGetQuadrangleSubPix(const Mat& src, Mat& dst, Mat& m) 150 | { 151 | CV_Assert(src.channels() == dst.channels()); 152 | 153 | cv::Size win_size = dst.size(); 154 | double matrix[6]; 155 | cv::Mat M(2, 3, CV_64F, matrix); 156 | m.convertTo(M, CV_64F); 157 | double dx = (win_size.width - 1)*0.5; 158 | double dy = (win_size.height - 1)*0.5; 159 | matrix[2] -= matrix[0] * dx + matrix[1] * dy; 160 | matrix[5] -= matrix[3] * dx + matrix[4] * dy; 161 | 162 | if (src.depth() == CV_8U && dst.depth() == CV_32F) 163 | getQuadrangleSubPix_8u32f_CnR(src.data, src.step, src.size(), 164 | (float*)dst.data, dst.step, dst.size(), 165 | matrix, src.channels()); 166 | else 167 | { 168 | CV_Assert(src.depth() == dst.depth()); 169 | cv::warpAffine(src, dst, M, dst.size(), 170 | cv::INTER_LINEAR + cv::WARP_INVERSE_MAP, 171 | cv::BORDER_REPLICATE); 172 | } 173 | } 174 | //---------------------------------------------------------- 175 | // Extracts rotated region and returns it as dst image 176 | //---------------------------------------------------------- 177 | void getRotRectImg(cv::RotatedRect rr, Mat &img, Mat& dst) 178 | { 179 | if (dst.empty() || dst.cols != rr.size.width || dst.rows != rr.size.height) 180 | { 181 | dst = cv::Mat(rr.size.height, rr.size.width, img.type()); 182 | } 183 | Mat m(2, 3, CV_64FC1); 184 | float ang = rr.angle * CV_PI / 180.0; 185 | m.at(0, 0) = cos(ang); 186 | m.at(1, 0) = sin(ang); 187 | m.at(0, 1) = -sin(ang); 188 | m.at(1, 1) = cos(ang); 189 | m.at(0, 2) = rr.center.x; 190 | m.at(1, 2) = rr.center.y; 191 | myGetQuadrangleSubPix(img, dst, m); 192 | } 193 | //---------------------------------------------------------- 194 | // Copies image region (src_roi) from src image, to rotated region on image dst 195 | //---------------------------------------------------------- 196 | void copyToRotRectImg(cv::Rect src_roi, cv::RotatedRect rr, Mat &src, Mat& dst) 197 | { 198 | float w = rr.size.width / 2; 199 | float h = rr.size.height / 2; 200 | Mat m(2, 3, CV_64FC1); 201 | float ang = rr.angle * CV_PI / 180.0; 202 | m.at(0, 0) = cos(ang); 203 | m.at(1, 0) = sin(ang); 204 | m.at(0, 1) = -sin(ang); 205 | m.at(1, 1) = cos(ang); 206 | m.at(0, 2) = rr.center.x - w*cos(ang) + h*sin(ang); 207 | m.at(1, 2) = rr.center.y - w*sin(ang) - h*cos(ang); 208 | Size rs = dst.size(); 209 | Mat tmp = src(src_roi).clone(); 210 | resize(tmp, tmp, rr.size); 211 | warpAffine(tmp, dst, m, rs, INTER_CUBIC, BORDER_TRANSPARENT, Scalar::all(0)); 212 | } 213 | //---------------------------------------------------------- 214 | // Copies image src, to rotated region on image dst 215 | //---------------------------------------------------------- 216 | void copyToRotRectImg(cv::RotatedRect rr, Mat &src, Mat& mask, Mat& dst) 217 | { 218 | cv::Rect src_roi = Rect(0, 0, src.cols, src.rows); 219 | float w = rr.size.width / 2; 220 | float h = rr.size.height / 2; 221 | Mat m(2, 3, CV_64FC1); 222 | float ang = rr.angle * CV_PI / 180.0; 223 | m.at(0, 0) = cos(ang); 224 | m.at(1, 0) = sin(ang); 225 | m.at(0, 1) = -sin(ang); 226 | m.at(1, 1) = cos(ang); 227 | m.at(0, 2) = rr.center.x - w*cos(ang) + h*sin(ang); 228 | m.at(1, 2) = rr.center.y - w*sin(ang) - h*cos(ang); 229 | Size rs = dst.size(); 230 | 231 | Mat tmp = src.clone(); 232 | resize(tmp, tmp, rr.size); 233 | 234 | Mat tmp_m = mask.clone(); 235 | resize(tmp_m, tmp_m, rr.size); 236 | 237 | Mat dst_1 = dst.clone(); 238 | warpAffine(tmp, dst_1, m, rs, INTER_CUBIC, BORDER_TRANSPARENT, Scalar::all(0)); 239 | Mat dst_m = Mat::zeros(dst.size(), CV_8UC1); 240 | warpAffine(tmp_m, dst_m, m, rs, INTER_CUBIC, BORDER_TRANSPARENT, Scalar::all(0)); 241 | 242 | dst_m.convertTo(dst_m, CV_32F, 1.0 / 255.0); 243 | dst.convertTo(dst, CV_32F); 244 | dst_1.convertTo(dst_1, CV_32F); 245 | dst = dst.mul(Scalar::all(1) - dst_m) + dst_1.mul(dst_m); 246 | dst.convertTo(dst, CV_8U); 247 | //dst_1.copyTo(dst, dst_m); 248 | } 249 | //---------------------------------------------------------- 250 | // Draws rotated rectangle 251 | //---------------------------------------------------------- 252 | void drawRR(cv::Mat &img, cv::RotatedRect rr, Scalar color, int width) 253 | { 254 | Point2f rect_points[4]; 255 | rr.points(rect_points); 256 | for (int j = 0; j < 4; j++) 257 | { 258 | line(img, rect_points[j], rect_points[(j + 1) % 4], color, width, cv::LINE_AA); 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /RR_Lib.h: -------------------------------------------------------------------------------- 1 | #include "opencv2/opencv.hpp" 2 | namespace RRLib { 3 | //---------------------------------------------- 4 | // Check if rotated box contained in image region 5 | //---------------------------------------------- 6 | bool boxInRange(cv::Mat& img, cv::RotatedRect& r); 7 | //---------------------------------------------- 8 | // Check if rotated box contained in rectangular region 9 | //---------------------------------------------- 10 | bool boxInRange(cv::Rect r, cv::RotatedRect& rr); 11 | //---------------------------------------------------------- 12 | // Extracts rotated region and returns it as dst image 13 | //---------------------------------------------------------- 14 | void getRotRectImg(cv::RotatedRect rr, cv::Mat &img, cv::Mat& dst); 15 | //---------------------------------------------------------- 16 | // Copies image region (src_roi) from src image, to rotated region on image dst 17 | //---------------------------------------------------------- 18 | void copyToRotRectImg(cv::Rect src_roi, cv::RotatedRect rr, cv::Mat &src, cv::Mat& dst); 19 | //---------------------------------------------------------- 20 | // Copies image src, to rotated region on image dst 21 | //---------------------------------------------------------- 22 | void copyToRotRectImg(cv::RotatedRect rr, cv::Mat &src, cv::Mat& mask, cv::Mat& dst); 23 | //---------------------------------------------------------- 24 | // Draws rotated rectangle 25 | //---------------------------------------------------------- 26 | void drawRR(cv::Mat &img, cv::RotatedRect rr, cv::Scalar color, int width); 27 | } -------------------------------------------------------------------------------- /lena.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Smorodov/RotatedRectLib/59911f8d91d5d43869bfe4eace8b0c155aba2128/lena.jpg -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "RR_Lib.h" 2 | using namespace std; 3 | using namespace cv; 4 | //----------------------------------------------------------------------------------------------------- 5 | // 6 | //----------------------------------------------------------------------------------------------------- 7 | int main(int argc, char** argv) 8 | { 9 | Mat img = cv::imread("../lena.jpg", 1); 10 | Mat img_bak = img.clone(); 11 | if (img.empty()) 12 | { 13 | return 0; 14 | } 15 | 16 | // Set rotated region to extract fragment 17 | RotatedRect rr; 18 | rr.center = cv::Point2f(256, 256); 19 | rr.angle = 10; 20 | rr.size.width = 150; 21 | rr.size.height = 150; 22 | 23 | Mat fragment; 24 | // Extract fragment 25 | RRLib::getRotRectImg(rr, img, fragment); 26 | // Show where we extracted it from 27 | RRLib::drawRR(img, rr, cv::Scalar(255, 0, 0),2); 28 | imshow("extracted fragment", fragment); 29 | imshow("extracting fragment", img); 30 | 31 | // restore image 32 | img = img_bak.clone(); 33 | // get piece of image 34 | cv::Rect src_roi = Rect(0, 0, fragment.cols, fragment.rows); 35 | // set target roi 36 | rr.center = cv::Point2f(300, 300); 37 | rr.angle = -30; 38 | // paste it to image 39 | RRLib::copyToRotRectImg(src_roi, rr, fragment, img); 40 | // draw frame around 41 | RRLib::drawRR(img, rr, cv::Scalar(255, 0, 255), 2); 42 | imshow("inserted fragment simple", img); 43 | 44 | 45 | // restore image 46 | img = img_bak.clone(); 47 | rr.center = cv::Point2f(150, 350); 48 | rr.angle = -60; 49 | 50 | // create mask 51 | Mat mask = Mat::zeros(fragment.size(), CV_8UC3); 52 | circle(mask, Point(fragment.cols / 2, fragment.rows / 2), fragment.rows / 2, Scalar::all(255),-1); 53 | GaussianBlur(mask, mask, Size(25, 25), 17); 54 | normalize(mask, mask, 0, 255, cv::NORM_MINMAX); 55 | 56 | // paste with mask (it really blending) 57 | RRLib::copyToRotRectImg(rr, fragment,mask, img); 58 | RRLib::drawRR(img, rr, cv::Scalar(255, 0, 255), 2); 59 | imshow("inserted fragment with mask", img); 60 | 61 | waitKey(); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /result.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Smorodov/RotatedRectLib/59911f8d91d5d43869bfe4eace8b0c155aba2128/result.PNG --------------------------------------------------------------------------------