具体说明参照上述资料。在此基础上做了部分修改或者说优化:
1、直接使用3通道的原图查找边界点,不再转换成灰度图及二值化图像,提高效率。应用范围也是和之前类似,夜景图片效果会不好。这个修改可以提高部分性能。
2、第一次找到对角非全黑点后,会尝试往回找,尽量增大可用面积。
代码如下:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
cv::Mat OpenCVTest::quchuHeibian(cv::Mat& img)
{
qDebug() << "img channels = " << img.channels() << endl;
int nOffSet = 1;//偏移量,防止弧度极小时,不能往回退
unsigned long AAtime = 0, BBtime = 0; //check processing time
AAtime = cv::getTickCount(); //check processing time
cv::Point2i leftTopPt;
for (int i = 1; i < img.rows; ++i) {
Vec3b& bgra = img.at<Vec3b>(i, i);
if (!(bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0)) { //不等于黑色
leftTopPt.x = i;
leftTopPt.y = i;
int x = leftTopPt.x - 1;
for (; x > 0; --x) {//从第x列到第0列,往回找到最近一个黑点
Vec3b& bgra = img.at<Vec3b>(leftTopPt.y + nOffSet, x);
if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
break;
}
}
if (leftTopPt.x != x + 1)
{
leftTopPt.x = x + 1;
leftTopPt.y += nOffSet;
}
int y = leftTopPt.y - 1;
for (; y > 0; --y) {//从第y行到第0行,往回找到最近一个黑点
Vec3b& bgra = img.at<Vec3b>(y, leftTopPt.x + nOffSet);
if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
break;
}
}
if (leftTopPt.y != y + 1)
{
leftTopPt.y = y + 1;
leftTopPt.x += nOffSet;
}
break;
}
}
cv::Point2i rightTopPt;
for (int i = 1; i < img.rows; ++i) {
int x = img.cols - i;
int y = i;
Vec3b& bgra = img.at<Vec3b>(y, x);
if (!(bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0)) { //不等于黑色
rightTopPt.x = x;
rightTopPt.y = y;
x = rightTopPt.x + 1;
for (; x < img.cols; ++x) {//从第x列到最后一列,往回找到最近一个黑点
Vec3b& bgra = img.at<Vec3b>(rightTopPt.y + nOffSet, x);
if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
break;
}
}
if (rightTopPt.x != x - 1)
{
rightTopPt.x = x - 1;
rightTopPt.y += nOffSet;
}
y = rightTopPt.y - 1;
for (; y > 0; --y) {//从第y行到第0行,往回找到最近一个黑点
Vec3b& bgra = img.at<Vec3b>(y, rightTopPt.x - nOffSet);
if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
break;
}
}
if (rightTopPt.y != y + 1)
{
rightTopPt.y = y + 1;
rightTopPt.x -= nOffSet;
}
break;
}
}
cv::Point2i leftBottomPt;
for (int i = 1; i < img.rows; ++i) {
int x = i;
int y = img.rows - i;
Vec3b& bgra = img.at<Vec3b>(y, x);
if (!(bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0)) { //不等于黑色
leftBottomPt.x = x;
leftBottomPt.y = y;
x = leftBottomPt.x - 1;
for (; x > 0; --x) {//从第x列到第0列,往回找到最近一个黑点
Vec3b& bgra = img.at<Vec3b>(leftBottomPt.y - nOffSet, x);
if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
break;
}
}
if (leftBottomPt.x != x + 1)
{
leftBottomPt.x = x + 1;
leftBottomPt.y -= nOffSet;
}
y = leftBottomPt.y + 1;
for (; y < img.rows; ++y) {//从第y行到最后一行,往回找到最近一个黑点
Vec3b& bgra = img.at<Vec3b>(y, leftBottomPt.x + nOffSet);
if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
break;
}
}
if (leftBottomPt.y != y - 1)
{
leftBottomPt.y = y - 1;
leftBottomPt.x += nOffSet;
}
break;
}
}
cv::Point2i rightBottomPt;
for (int i = 1; i < img.rows; ++i) {
int x = img.cols - i;
int y = img.rows - i;
Vec3b& bgra = img.at<Vec3b>(y, x);
if (!(bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0)) { //不等于黑色
rightBottomPt.x = x;
rightBottomPt.y = y;
x = rightBottomPt.x + 1;
for (; x < img.cols; ++x) {//从第x列到最后一列,往回找到最近一个黑点
Vec3b& bgra = img.at<Vec3b>(rightBottomPt.y - nOffSet, x);
if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
break;
}
}
if (rightBottomPt.x != x - 1)
{
rightBottomPt.x = x - 1;
rightBottomPt.y -= nOffSet;
}
y = rightBottomPt.y + 1;
for (; y < img.rows; ++y) {//从第y行到最后一行,往回找到最近一个黑点
Vec3b& bgra = img.at<Vec3b>(y, rightBottomPt.x - nOffSet);
if (bgra[0] == 0 && bgra[1] == 0 && bgra[2] == 0) { //等于黑色
break;
}
}
if (rightBottomPt.y != y - 1)
{
rightBottomPt.y = y - 1;
rightBottomPt.x -= nOffSet;
}
break;
}
}
//测试代码1,begin
//cv::Scalar color2(255, 255, 0);
// 用黑白图片计算的结果,在原图画个小圆点(黑白图上画不够明显)
//cv::circle(img, leftTopPt, 5, color2, -1);
//cv::circle(img, rightTopPt, 5, color2, -1);
//cv::circle(img, leftBottomPt, 5, color2, -1);
//cv::circle(img, rightBottomPt, 5, color2, -1);
//cv::line(img, leftTopPt, rightTopPt, color2);
//cv::line(img, leftTopPt, leftBottomPt, color2);
//cv::line(img, rightTopPt, rightBottomPt, color2);
//cv::line(img, leftBottomPt, rightBottomPt, color2);
//测试代码1,end
int topMaxY = max(leftTopPt.y, rightTopPt.y);
int leftMaxX = max(leftTopPt.x, leftBottomPt.x);
int rightMinX = min(rightTopPt.x, rightBottomPt.x);
int bottomMinY = min(leftBottomPt.y, rightBottomPt.y);
leftTopPt.y = topMaxY;
rightTopPt.y = topMaxY;
leftTopPt.x = leftMaxX;
leftBottomPt.x = leftMaxX;
rightTopPt.x = rightMinX;
rightBottomPt.x = rightMinX;
leftBottomPt.y = bottomMinY;
rightBottomPt.y = bottomMinY;
//测试代码2,begin
//cv::Scalar color(10, 10, 255);
// 用黑白图片计算的结果,在原图画个小圆点(黑白图上画不够明显)
//cv::circle(img, leftTopPt, 5, color, -1);
//cv::circle(img, rightTopPt, 5, color, -1);
//cv::circle(img, leftBottomPt, 5, color, -1);
//cv::circle(img, rightBottomPt, 5, color, -1);
//cv::line(img, leftTopPt, rightTopPt, color);
//cv::line(img, leftTopPt, leftBottomPt, color);
//cv::line(img, rightTopPt, rightBottomPt, color);
//cv::line(img, leftBottomPt, rightBottomPt, color);
//测试代码2,end
Mat tempMat = img(cv::Rect(leftTopPt.x, leftTopPt.y, rightBottomPt.x - leftTopPt.x, rightBottomPt.y - leftTopPt.y));
BBtime = cv::getTickCount(); //check processing time
float costtime = (BBtime - AAtime) / cv::getTickFrequency();
QString costimeresult = QString("裁剪时间:%1").arg(costtime);
qInfo() << costimeresult;
return tempMat;
}