Qt、openCV讀取攝像頭,快速雙邊濾波實現視頻流美顏、磨皮,顯示

環境配置:opencv2.4.13 vs2015 Qt5.7.1

注意:

1、openCV自帶的磨皮、美白效果只能進行參考,性能不高,才採用快速雙邊濾波

2、示例中openCV只用來打開了攝像頭,可用系統自帶api替代;

3、需要先編譯jpeg.lib

處理步驟:

1:從攝像頭抓取一幀;

2:利用libjpeg將IplImage轉成jpeg;

3:快速雙邊濾波處理圖像;

4:unsigned char *轉QImage並顯示;

性能參數:線程數=4 ,i5處理器, 640*480爲30ms左右,fps可達30,效率非常高;

項目目的結構:

1、main.cpp

#include <QtWidgets/QApplication>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
#include "cameratest.h"
int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	CameraTest w;
	w.show();
	return a.exec();
}

2、cameratest.h cameratest.cpp cameratest.ui

#ifndef CAMERATEST_H
#define CAMERATEST_H

#include <QtWidgets/QMainWindow>
#include "ui_cameratest.h"
#include "opencv2/core/core.hpp"    
#include "opencv2/highgui/highgui.hpp"    
#include "opencv2/imgproc/imgproc.hpp"    
#include <stdio.h>  
#include <opencv2/opencv.hpp>   

static float sigma_spatial = 0.05f;
static float sigma_range = 0.05f;

#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define _CRT_SECURE_NO_WARNINGS

#include <QImage>  
#include <QTimer>     // 設置採集數據的間隔時間
#include <QSlider>
using namespace cv;
class CameraTest : public QMainWindow
{
	Q_OBJECT

public:
	CameraTest(QWidget *parent = 0);
	~CameraTest();

private:
	Ui::CameraTestClass ui;
private slots:
	void openCamara();      // 打開攝像頭  
	void readFarme();       // 讀取當前幀信息  
	void closeCamara();     // 關閉攝像頭。  
	void horizontalSliderChanged(int);
	void horizontalSliderChanged2(int);
private:
	QTimer    *timer;
	QImage    *imag;

	CvCapture *cam;// 視頻獲取結構, 用來作爲視頻獲取函數的一個參數  
	IplImage  *frame;//申請IplImage類型指針,就是申請內存空間來存放每一幀圖像
};

#endif // CAMERATEST_H
#include "cameratest.h"
#include <time.h>
#include <iostream>
#include "stb_image.h"
#include "RBFilter_AVX2.h"
#include "jpeg-9\jpeglib.h"
#include "crbfilter.h"
#include "stb_image_write.h"
using namespace std;
class TestRunTimer
{
	clock_t begTime;

public:
	void start() { begTime = clock(); }
	float elapsedTimeMS() { return float(clock() - begTime); }
};

unsigned char * testRunRecursiveBF_AVX2_mt(unsigned char * image, int len, int thread_count, bool multiThread = true)
{
	int width, height, channel;
	unsigned char * img = stbi_load_from_memory((stbi_uc*)image, len, &width, &height, &channel, 4);
	if (!img)
	{
		return NULL;
	}
	channel = 4;

	unsigned char * img_out;
	if (multiThread)
	{
		CRBFilterAVX2 rbf_object;
		bool success = rbf_object.initialize(width, height, thread_count, false);
		if (!success)
		{
			delete[] img;
			return nullptr;
		}
		rbf_object.setSigma(sigma_spatial, sigma_range);

		int pitch = rbf_object.getOptimalPitch(width);
		img_out = (unsigned char*)_aligned_malloc(pitch * height, 32);

		unsigned char* buffer = (unsigned char*)_aligned_malloc(pitch * height, 32);
		for (int y = 0; y < height; y++)
		{
			memcpy(buffer + y * pitch, img + y * width * 4, width * 4);
		}
		delete[] img;
		img = buffer;

		success = rbf_object.filter(img_out, img, width, height, pitch);

		if (!success)
			return nullptr;
	}
	else
	{
		CRBFilter rbf_object;

		int pitch = rbf_object.getOptimalPitch(width);

		img_out = (unsigned char*)_aligned_malloc(pitch * height, 32);
		unsigned char* buffer = (unsigned char*)_aligned_malloc(pitch * height, 32);
		for (int y = 0; y < height; y++)
		{
			memcpy(buffer + y * pitch, img + y * width * 4, width * 4);
		}
		delete[] img;
		img = buffer;

		rbf_object.CRB_Filter(img, img_out, width, height, pitch, sigma_spatial, sigma_range);
	}

	_aligned_free(img);
	return img_out;
}

static bool jpegSave(const char* filename, unsigned char *outbuffer, unsigned long outlen)
{
	FILE *f;
	fopen_s(&f, filename, "wb");
	if (!f)
		return false;

	size_t size = fwrite(outbuffer, (size_t)outlen, 1, f);
	fclose(f);


	if (size == 1)
		return true;

	return false;
}
/*********************************
********* IplImage轉jpeg *********
**********************************/
static bool ipl2jpeg(IplImage *img, unsigned char **outbuffer, unsigned long outlen)
{
	unsigned char *outdata = (uchar *)img->imageData;
	struct jpeg_compress_struct cinfo = { 0 };
	struct jpeg_error_mgr jerr;
	JSAMPROW row_ptr[1];
	int row_stride;

	*outbuffer = NULL;
	outlen = 0;

	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);


	cinfo.image_width = img->width;
	cinfo.image_height = img->height;
	cinfo.input_components = img->nChannels;
	cinfo.in_color_space = JCS_RGB;

	jpeg_mem_dest(&cinfo, outbuffer, &outlen);

	jpeg_set_defaults(&cinfo);
	jpeg_start_compress(&cinfo, TRUE);
	row_stride = img->width * img->nChannels;


	while (cinfo.next_scanline < cinfo.image_height)
	{
		row_ptr[0] = &outdata[cinfo.next_scanline * row_stride];
		jpeg_write_scanlines(&cinfo, row_ptr, 1);
	}

	jpeg_finish_compress(&cinfo);
	jpeg_destroy_compress(&cinfo);

	return true;
}
CameraTest::CameraTest(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	cam = NULL;
	timer = new QTimer(this);
	imag = new QImage();         // 初始化  

								 /*信號和槽*/
	connect(timer, SIGNAL(timeout()), this, SLOT(readFarme()));  // 時間到,讀取當前攝像頭信息  
	connect(ui.open, SIGNAL(clicked()), this, SLOT(openCamara()));
	connect(ui.closeCam, SIGNAL(clicked()), this, SLOT(closeCamara()));
	connect(ui.horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(horizontalSliderChanged(int)));
	connect(ui.horizontalSlider_2, SIGNAL(valueChanged(int)), this, SLOT(horizontalSliderChanged2(int)));
	ui.horizontalSlider->setValue(5);
	ui.horizontalSlider->setMaximum(10);
	ui.horizontalSlider_2->setValue(5);
	ui.horizontalSlider_2->setMaximum(10);
}
void CameraTest::horizontalSliderChanged(int value)
{
	int a = ui.horizontalSlider->value();
	sigma_spatial = 0.01*value;
	
}
void CameraTest::horizontalSliderChanged2(int value)
{
	int a = ui.horizontalSlider_2->value();
	sigma_range = 0.01*value;
}
CameraTest::~CameraTest()
{

}
void CameraTest::openCamara()
{
	cam = cvCreateCameraCapture(0);//打開攝像頭,從攝像頭中獲取視頻  
	timer->start(30);              // 開始計時,超時則發出timeout()信號  1024/30 == fps
}
//
//TestRunTimer timer;
//timer.start();
//cout << ", QImage image---time ms: " << timer.elapsedTimeMS();
/*********************************
********* 讀取攝像頭信息 ***********
**********************************/
void CameraTest::readFarme()
{
	unsigned char * buffer;
	unsigned long  len;
	frame = cvQueryFrame(cam);
	
	ipl2jpeg(frame, &buffer, len);

	unsigned char * outImg = testRunRecursiveBF_AVX2_mt(buffer, len, 1,true);

	QImage image((const uchar*)outImg, frame->width, frame->height, QImage::Format_ARGB32);
	ui.label->setPixmap(QPixmap::fromImage(image));
	_aligned_free(outImg);
	free(buffer);
}

/*******************************
***關閉攝像頭,釋放資源,必須釋放***
********************************/
void CameraTest::closeCamara()
{
	timer->stop();         // 停止讀取數據。  

	cvReleaseCapture(&cam);//釋放內存; 
}

3、crbfilter.h crbfilter.cpp RBFilter_AVX2.h RBFilter_AVX2.cpp 參考:快速雙邊濾波處理算法:https://www.cnblogs.com/cpuimage/p/7629304.html

jpeg-9源碼

https://download.csdn.net/download/u013495598/11078766

Qt、openCV讀取攝像頭,快速雙邊濾波實現視頻流美顏、磨皮,顯示demo

https://download.csdn.net/download/u013495598/11078798

也可以郵件至[email protected],發demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章