【发布时间】:2020-05-04 20:36:55
【问题描述】:
【问题讨论】:
-
首先是编写一些人们可以提供输入的代码。目前,只有两张照片。有人能对这些说些什么吗?创建minimal reproducible example。
标签: c++ image opencv image-processing computer-vision
【问题讨论】:
标签: c++ image opencv image-processing computer-vision
这个想法是对每一列的像素求和,然后遍历数据以构建新图像。如果一列的值为零,则表示它是黑色的,因此我们忽略它,否则我们将列 ROI 连接到最终图像。这是列像素的总和:
结果
我在 Python 中实现了它,但您可以将类似的想法应用于 C++
import cv2
import numpy as np
# import matplotlib.pyplot as plt
# Load image, convert to grayscale, and sum column pixels
image = cv2.imread('1.jpg')
h, w = image.shape[:2]
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
first_pass = True
pixels = np.sum(gray, axis=0).tolist()
# Build new image
for index, value in enumerate(pixels):
if value == 0:
continue
else:
ROI = image[0:h, index:index+1]
if first_pass:
result = image[0:h, index+1:index+2]
first_pass = False
continue
result = np.concatenate((result, ROI), axis=1)
cv2.imshow('result', result)
cv2.imwrite('result.png', result)
# Uncomment for plot visualization
# plt.plot(pixels, color='teal')
# plt.show()
cv2.waitKey()
【讨论】:
注意: 根据 nathancy 的回答,我刚刚使用 C++ 进行了编码:
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("/your/image/directory/image.jpg");
for(int i=0;i<img.cols;i++)
{
int black_cnt = 0;
for(int j=0;j<img.rows;j++)
{
if(img.at<cv::Vec3b>(j,i)[0]==0)
black_cnt++;
}
if(black_cnt==img.rows)
continue;
else
{
Rect roi(i,0,img.cols-i,img.rows);
img = img(roi);
break;
}
}
imshow("Result",img);
waitKey(0);
return 0;
}
【讨论】:
快速的方法是使用 OpenCv 的cv::reduce 函数并找到每列的最大值。它比制作元素的总和要快。如果列中的最大值为0,则表示该列是黑色的。
cv::reduce 的输入是二维数组:
[a b c]
[d e f]
[g h i]
作为输出将得到矩阵 2d 与一行 - 向量。
[max(a,d,g) max(b,e,h) max(c,f,i)]
然后你需要找到cutOff index - 第一个非黑色列,并提取ROI:
cv::Mat img = imread("test.jpg");
cv::Mat out;
cv::reduce(img, out, 0, cv::REDUCE_MAX);
int cutOffIdx = 0;
for (int col = 0; col < out.cols; ++col) {
const cv::Vec3b& vec = out.at<Vec3b>(0, col);
if (vec[0] || vec[1] || vec[2]) {
cutOffIdx = col;
break;
}
}
cv::imshow("test",img(cv::Rect(cutOffIdx,0,img.cols-cutOffIdx-1,img.rows)));
cv::waitKey(0);
【讨论】:
我会这样做:
灰度图像阈值化
在图像中寻找最外层的轮廓
从等高线中找出最大的那个
获取该轮廓的边界框
通过该边界框裁剪图像
以及代码(C++ opencv):
Mat K,J,I = imread("D:/1.jpg",1);
cvtColor(I, K, CV_BGR2GRAY);
threshold(K, J, 0, 255, THRESH_BINARY);
vector<vector<Point>> contours;
vector< Vec4i > hierarchy;
findContours(J, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE); # Gives the outer contours
Mat tmp = Mat::zeros(I.size(), CV_8U);
int k = 0;
double max = -1;
for (size_t i = 0; i < contours.size(); i++) # Of course in this case, There is only one external contour but I write the loop for more clarification
{
double area = contourArea(contours[i]);
if (area > max)
{
k = i;
max = area;
}
}
drawContours(tmp, contours, k, Scalar(255, 255, 255), -1); # You can comment this line. I wrote it just for showing the procedure
Rect r = cv::boundingRect(contours[k]);
Mat output;
I(r).copyTo(output);
imshow("0", I);
imshow("1", J);
imshow("2", tmp);
imshow("3", output);
waitKey(0);
【讨论】: