记一次24色卡LAB的过程

最近要做个24色卡相关工作,随便打印了一张,用手机拍照成图如下:

24色卡图

 

拍完照就顺手发到qq群看看是不是能白嫖到相关代码,例如怎么定位到每个色块?高手还是很多的,一位大佬马上给出了方案 canny+膨胀+findContours 而且不一会大佬给出了其代码运行结果如图:

 

简直堪称完美迅速啊!!! ... 估计大佬为了督促我学习,没有给具体代码 所以我自己一步一步的来 ...

首先canny是找边缘,也听过梯度,我这里首先对图片X 和 Y 分别求梯度然后如何其结果得到如下边缘图:

梯度边缘图

最后我简单阈值后使用findContours函数得到的结果如下:

结果一

从中很明显能看出有的色块框没有被框出来,有的色块框了几次 ... 代码如下:

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/video.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include <iostream>
#include <fstream>
#include<iomanip>


using namespace std;
using namespace cv;

int main(int argc, const char** argv)
{
	// 加载图像到内存
	Mat myImg = imread("C:\\Users\\Administrator\\Desktop\\IMG_20210324_174937.jpg", IMREAD_COLOR);

	// 判断图像是否存在
	if (myImg.empty())
	{
		cout << "could not find image..." << endl;
		return -1;
	}

	Mat showimg = myImg.clone();
	cvtColor(showimg, showimg, CV_RGB2GRAY);
	imwrite("1.灰度图.jpg", showimg);

	Mat imageX16S, imageY16S;
	Mat imageSobelX, imageSobelY, imageSobelOut;
	Sobel(showimg, imageX16S, CV_16S, 1, 0, 3, 1, 0, 4);
	Sobel(showimg, imageY16S, CV_16S, 0, 1, 3, 1, 0, 4);
	convertScaleAbs(imageX16S, imageSobelX, 1, 0);
	convertScaleAbs(imageY16S, imageSobelY, 1, 0);
	imageSobelOut = imageSobelX + imageSobelY;
	imwrite("2.1X方向梯度.jpg", imageSobelX);
	imwrite("2.2Y方向梯度.jpg", imageSobelY);
	imwrite("2.3XY方向梯度差.jpg", imageSobelOut);

	Mat imageSobleOutThreshold;
	threshold(imageSobelOut, imageSobleOutThreshold, 18, 255, CV_THRESH_BINARY);
	imwrite("3.二值化.jpg", imageSobleOutThreshold);

	vector<vector<Point> > contours_all;
	vector<Vec4i> hierarchy_all;
	double timeAt;
	timeAt = static_cast<double>(getTickCount());
	findContours(imageSobleOutThreshold, contours_all, hierarchy_all, RETR_TREE, CHAIN_APPROX_NONE);
	timeAt = ((double)getTickCount() - timeAt) / getTickFrequency();
	cout << "findContours计算耗时:" << timeAt << endl << endl;

	for (int i = 0; i < contours_all.size(); i++)
	{
		Rect rect = boundingRect((Mat)contours_all[i]);
		double height = rect.height, width = rect.width;
		double rate = height / width;
		if (rect.height < 550 || rect.height > 800 || rate > 1.2 || rate < 0.8) {
			continue;
		}
		rectangle(myImg, rect, (255), 10);
	}
	imwrite("4.找出矩形区域.jpg", myImg);
	waitKey(0);
	return 0;
}

上面的有问题,接着我又换个办法,首先我能不能根据每个色块的RGB的值先处理一下,把色块区域整成白色,色块周围的整成黑色这样处理后再来找框...

例如色块中每个像素点的RGB差异应该大于其周围区域每个像素点RGB的差异,在电脑上可以事先了解每个色块中像素点RGB的差异值,例如RGB差异值大于10,但是事实上在代码中时,利用这个差值效果并不明显,不知是不是电脑读出的每个像素点RGB和opencv读出的RGB不一样的缘故

根据实际操作,我代码中是差1 详见下面代码,另外对最后找到的框,有的偏大有的偏小,但这里并不影响到我的实际应用场景,因为我只要找到色块框,然后在里面取一个像素点,读取其LAB值就好.但是这里又有另外一个问题,例如取的那个点刚好是所拍照片中的瑕疵点呢?? ---- 其实这里可以首先对图片做一次平滑滤波处理,先剔除掉有关瑕疵点...参考代码如下:

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/video.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include <iostream>
#include <fstream>
#include<iomanip>

using namespace std;
using namespace cv;

int main(int argc, const char** argv) {
	Mat myImg = imread("C:\\Users\\Administrator\\Desktop\\IMG_20210324_174937.jpg", IMREAD_COLOR);

	if (myImg.empty())
	{
		cout << "could not find image..." << endl;
		return -1;
	}

	Mat colorImage = myImg.clone();

	medianBlur(colorImage, colorImage, 3);

	for (int i = 0; i < colorImage.rows; ++i)
	{
		Vec3b* p = colorImage.ptr<Vec3b>(i);
		for (int j = 0; j < colorImage.cols; ++j)
		{
			if (abs(p[j][0] - p[j][1]) + abs(p[j][0] - p[j][1]) + abs(p[j][0] - p[j][1]) > 3) {
				p[j][0] = 255;
				p[j][1] = 255;
				p[j][2] = 255;
			}
			else
			{
				p[j][0] = 0;
				p[j][1] = 0;
				p[j][2] = 0;
			}
		}
	}

	cvtColor(colorImage, colorImage, CV_RGB2GRAY);

	Mat  element = getStructuringElement(0, Size(20, 20));

	erode(colorImage, colorImage, element);
	dilate(colorImage, colorImage, element);

	vector<vector<Point> > contours_all;
	vector<Vec4i> hierarchy_all;
	double timeAt;
	timeAt = static_cast<double>(getTickCount());
	findContours(colorImage, contours_all, hierarchy_all, RETR_TREE, CHAIN_APPROX_NONE);
	timeAt = ((double)getTickCount() - timeAt) / getTickFrequency();
	cout << "findContours计算耗时:" << timeAt << endl << endl;

	Mat labImg;
	cvtColor(myImg, labImg, COLOR_BGR2Lab);

	double L = 0.0, A = 0.0, B = 0.0;
	// 建立输出文件流
	ofstream ofile;
	ofile.open("24seka3.txt");
	ofile << "24seka.png每一像素的LAB值:" << endl;
	ofile << "序号\t坐标\tL\tA\tB" << endl;

	int w = 0;
	int h = 0;

	for (int i = 0; i < contours_all.size(); i++)
	{
		Rect rect = boundingRect((Mat)contours_all[i]);
		double height = rect.height, width = rect.width;
		double rate = height / width;
		if (rect.height < 400 || rect.height > 800 || rate > 1.3 || rate < 0.7) {
			continue;
		}
		rectangle(myImg, rect, (255), 10);

		w = rect.x + rect.width / 2;
		h = rect.y + rect.height / 2;

		// 读取每一点LAB值,存在L,A,B变量中。
		L = labImg.at<Vec3b>(w, h)[0];
		A = labImg.at<Vec3b>(w, h)[1];
		B = labImg.at<Vec3b>(w, h)[2];

		L = L * 100 / 255;
		A = A - 128;
		B = B - 128;

		cout << "像素点(" << w << "," << h << ")的LAB值为:"
			<< " L: " << L << " A: " << A << " B: " << B << endl;

		// 将图片的LAB值写入文件
		ofile << w * labImg.rows + h << "\t" << "(" << w << "," << h << ")" << "\t" << L << "\t"
			<< A << "\t" << B << endl;
	}
	imwrite("找出矩形区域.jpg", myImg);
	waitKey(0);
	return 0;
}

得到的框框图见下:

得到的LAB值如下:

色块区域的lab值

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值