Windows下使用QT+OpenCV完成人脸检测(获取摄像头的数据进行检测)_qtopencv人脸检测-程序员宅基地

技术标签: qt  qt开发  opencv  

一、环境介绍

Windows版本: Win10 X64

OpenCV版本: 2.4.13.6

QT版本: 5.12

二、OpenCV库下载

OpenCV官网下载地址: ​ ​https://opencv.org​​​

 

 

目前官网OpenCV最新的版本是4.2.0 ,Windows版本的OpenCV在3.X版本后就不带X86的库,只有X64的库,如果需要X86的库,需要自己下载源码去重新编译。

由于我的QT软件在安装时没有安装64位的编译器,又不想重新安装64位编译器,就选择了2.X的版本完成开发测试,3.X的版本在添加库的时候非常方便,就一个库。

库下载之后,双击运行,解压到指定的目录就行。

 

 

接下来要把OpenCV的动态库目录加到系统环境变量里,否则程序运行时找不到依赖库会崩溃。

 

 

三、程序思路说明

程序功能: 在子线程里打开摄像头,获取摄像头的数据,通过信号与槽的方式,将摄像头数据传递给主UI界面实时显示,在采用定时器每100ms取一次标签上的数据进行人脸检测处理,将处理的数据再显示到另一个标签上。人脸检测分类器采用OpenCV自带的分类器,程序主要目的是介绍OpenCV配合QT如何进行开发。

OpenCV自带的人脸检测分类器路径:C:/OpenCV_2.4/opencv/sources/data/haarcascades_GPU/haarcascade_frontalface_alt2.xml

四、实现效果

 

五、核心代码

xxx.pro工程文件代码:

QT += core gui
QT += multimediawidgets
QT += xml
QT += multimedia
QT += network
QT += widgets
QT += serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
main.cpp \
widget.cpp

HEADERS += \
widget.h

FORMS += \
widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

#linu平台的路径设置
linux {
message('运行linu版本')
#添加opencv头文件的路径,需要根据自己的头文件路径进行修改
INCLUDEPATH+=/home/wbyq/work_pc/opencv-3.4.9/_install/install/include\
/home/wbyq/work_pc/opencv-3.4.9/_install/install/include/opencv\
/home/wbyq/work_pc/opencv-3.4.9/_install/install/include/opencv2

LIBS+=/home/wbyq/work_pc/opencv-3.4.9/_install/install/lib/libopencv_*
}

win32
{
message('运行win32版本')
#添加opencv头文件的路径,需要根据自己的头文件路径进行修改
INCLUDEPATH+=C:/OpenCV_2.4/opencv/build/include \
C:/OpenCV_2.4/opencv/build/include/opencv \
C:/OpenCV_2.4/opencv/build/include/opencv2
LIBS+=C:/OpenCV_2.4/opencv/build/x86/vc14/lib/opencv_*
}

RESOURCES += \
image.qrc

widget.cpp文件代码:

#include "widget.h"
#include "ui_widget.h"
class VideoAudioEncode videoaudioencode_0;

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);

//驾驶室摄像头
//工作对象
videoRead_WorkClass_0=new VideoReadThread_0;
videoRead_Workthread_0=new QThread;
//连接摄像头采集信号,在主线程实时显示视频画面
connect(videoRead_WorkClass_0,SIGNAL(VideoDataOutput(QImage )),this,SLOT(VideoDataDisplay_0(QImage )));
//摄像头初始化函数
connect(this,SIGNAL(Init_VideoAudio_WorkClass_0()),videoRead_WorkClass_0,SLOT(run()));
//停止视频采集
connect(this,SIGNAL(Stop_AudioVideo0_work_0()),videoRead_WorkClass_0,SLOT(stop()));
//将工作对象移动到子线程里工作
videoRead_WorkClass_0->moveToThread(videoRead_Workthread_0);
//更新设备列表
UpdateVideoAudiodDevice(ui->comboBox_video_0,ui->plainTextEdit_log_0);
//
timer.start(100);
connect(&timer,SIGNAL(timeout()), this, SLOT(update()));
timer.start(100);
}


Widget::~Widget()
{
delete ui;
}

//分类器的路径
#define source_xml_addr "C:/OpenCV_2.4/opencv/sources/data/haarcascades_GPU/haarcascade_frontalface_alt2.xml"

//将要检测的图片路径
#define source_pix_addr "D:/linux-share-dir/1.jpg"

//人脸检测代码
void Widget::opencv_face(QImage qImage)
{
QTime time;
time.start();

static CvMemStorage* storage = 0;
static CvHaarClassifierCascade* cascade = 0;
const char*cascade_name =source_xml_addr;
//加载分类器
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
if( !cascade )
{
Log_Display_0("分类器加载错误.\n");
return ;
}

//创建内存空间
storage = cvCreateMemStorage(0);

//加载需要检测的图片
//const char* filename =source_pix_addr;
//IplImage* img = cvLoadImage(filename, 1 );
IplImage* img = QImageToIplImage(&qImage);

if(img ==nullptr )
{
Log_Display_0("图片加载错误.\n");
return;
}

double scale=1.2;
static CvScalar colors[] = {
{
   {0,0,255}},{
   {0,128,255}},{
   {0,255,255}},{
   {0,255,0}},
{
   {255,128,0}},{
   {255,255,0}},{
   {255,0,0}},{
   {255,0,255}}
};//Just some pretty colors to draw with
IplImage* gray = cvCreateImage(cvSize(img->width,img->height),8,1);
IplImage* small_img=cvCreateImage(cvSize(cvRound(img->width/scale),cvRound(img->height/scale)),8,1);
cvCvtColor(img,gray, CV_BGR2GRAY);
cvResize(gray, small_img, CV_INTER_LINEAR);
cvEqualizeHist(small_img,small_img); //直方图均衡
cvClearMemStorage(storage);
double t = (double)cvGetTickCount();
CvSeq* objects = cvHaarDetectObjects(small_img,
cascade,
storage,
1.1,
2,
0/*CV_HAAR_DO_CANNY_PRUNING*/,
cvSize(30,30));
t = (double)cvGetTickCount() - t;
//遍历找到对象和周围画盒
for(int i=0;i<(objects->total);++i)
{
CvRect* r=(CvRect*)cvGetSeqElem(objects,i);
cvRectangle(img, cvPoint(r->x*scale,r->y*scale), cvPoint((r->x+r->width)*scale,(r->y+r->height)*scale), colors[i%8]);
}

for( int i = 0; i < (objects? objects->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( objects, i );
CvPoint center;
int radius;
center.x = cvRound((r->x + r->width*0.5)*scale);
center.y = cvRound((r->y + r->height*0.5)*scale);
radius = cvRound((r->width + r->height)*0.25*scale);
cvCircle(img, center, radius, colors[i%8], 3, 8, 0 );
}
show_face(img); //显示检测的结果
cvReleaseImage(&gray);
cvReleaseImage(&small_img);
//释放图片
cvReleaseImage(&img);
Log_Display_0(tr("耗时:%1 ms\n").arg(time.elapsed()));
}

/*将QImage图片转为opecv的qimage格式*/
IplImage *Widget::QImageToIplImage(const QImage * qImage)
{
int width = qImage->width();
int height = qImage->height();
CvSize Size;
Size.height = height;
Size.width = width;
IplImage *IplImageBuffer = cvCreateImage(Size, IPL_DEPTH_8U, 3);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
QRgb rgb = qImage->pixel(x, y);
CV_IMAGE_ELEM( IplImageBuffer, uchar, y, x*3+0 ) = qBlue(rgb);
CV_IMAGE_ELEM( IplImageBuffer, uchar, y, x*3+1 ) = qGreen(rgb);
CV_IMAGE_ELEM( IplImageBuffer, uchar, y, x*3+2 ) = qRed(rgb);
}
}
return IplImageBuffer;
}

/*将opecv的图片转为qimage格式*/
QImage *Widget::IplImageToQImage(IplImage *img)
{
QImage *qmg;
uchar *imgData=(uchar *)img->imageData;
qmg = new QImage(imgData,img->width,img->height,QImage::Format_RGB888);
*qmg=qmg->rgbSwapped(); //BGR格式转RGB
return qmg;
}

//显示检测的结果
void Widget::show_face(IplImage* img)
{
uchar *imgData=(uchar *)img->imageData;
QImage my_image=QImage(imgData,img->width,img->height,QImage::Format_RGB888);
my_image=my_image.rgbSwapped(); //BGR格式转RGB
QPixmap my_pix; //创建画图类
my_pix.convertFromImage(my_image);
/*在控件上显示*/
ui->label_display->setPixmap(my_pix);
}

//开始采集
void Widget::on_pushButton_Start_clicked()
{
//设置当前选择的摄像头
videoaudioencode_0.camera=video_dev_list.at(ui->comboBox_video_0->currentIndex());
Stop_VideoAudioEncode_0(true);
Start_VideoAudioEncode_Thread_0();
}

//析构函数
VideoReadThread_0::~VideoReadThread_0()
{

}

//停止视频采集
void VideoReadThread_0::stop()
{
qDebug()<<"停止视频采集--stop";
if(camera)
{
camera->stop();
delete camera;
camera=nullptr;
}
if(m_pProbe)
{
delete m_pProbe;
m_pProbe=nullptr;
}
}

//执行线程
void VideoReadThread_0::run()
{
stop();
Camear_Init();
qDebug()<<"摄像头开始采集数据";
}

void VideoReadThread_0::Camear_Init()
{
/*创建摄像头对象,根据选择的摄像头打开*/
camera = new QCamera(videoaudioencode_0.camera);
m_pProbe = new QVideoProbe;
if(m_pProbe != nullptr)
{
m_pProbe->setSource(camera); // Returns true, hopefully.
connect(m_pProbe, SIGNAL(videoFrameProbed(QVideoFrame)),this, SLOT(slotOnProbeFrame(QVideoFrame)), Qt::QueuedConnection);
}

/*配置摄像头捕 QCamera *camera;
QVideoProbe *m_pProbe;获模式为帧捕获模式*/
//camera->setCaptureMode(QCamera::CaptureStillImage); //如果在Linux系统下运行就这样设置
camera->setCaptureMode(QCamera::CaptureVideo);//如果在android系统下运行就这样设置

/*启动摄像头*/
camera->start();

/*设置摄像头的采集帧率和分辨率*/
QCameraViewfinderSettings settings;
settings.setPixelFormat(QVideoFrame::Format_YUYV); //设置像素格式 Android上只支持NV21格式
settings.setResolution(QSize(VIDEO_WIDTH,VIDEO_HEIGHT)); //设置摄像头的分辨率
camera->setViewfinderSettings(settings);
}

/**
* NV21是android相机默认格式
* @param data
* @param rgb
* @param width
* @param height
*/
void NV21_TO_RGB24(unsigned char *yuyv, unsigned char *rgb, int width, int height)
{
const int nv_start = width * height ;
int index = 0, rgb_index = 0;
uint8_t y, u, v;
int r, g, b, nv_index = 0,i, j;

for(i = 0; i < height; i++){
for(j = 0; j < width; j ++){
//nv_index = (rgb_index / 2 - width / 2 * ((i + 1) / 2)) * 2;
nv_index = i / 2 * width + j - j % 2;

y = yuyv[rgb_index];
u = yuyv[nv_start + nv_index ];
v = yuyv[nv_start + nv_index + 1];

r = y + (140 * (v-128))/100; //r
g = y - (34 * (u-128))/100 - (71 * (v-128))/100; //g
b = y + (177 * (u-128))/100; //b

if(r > 255) r = 255;
if(g > 255) g = 255;
if(b > 255) b = 255;
if(r < 0) r = 0;
if(g < 0) g = 0;
if(b < 0) b = 0;

index = rgb_index % width + (height - i - 1) * width;
//rgb[index * 3+0] = b;
//rgb[index * 3+1] = g;
//rgb[index * 3+2] = r;

//颠倒图像
//rgb[height * width * 3 - i * width * 3 - 3 * j - 1] = b;
//rgb[height * width * 3 - i * width * 3 - 3 * j - 2] = g;
//rgb[height * width * 3 - i * width * 3 - 3 * j - 3] = r;

//正面图像
rgb[i * width * 3 + 3 * j + 0] = b;
rgb[i * width * 3 + 3 * j + 1] = g;
rgb[i * width * 3 + 3 * j + 2] = r;

rgb_index++;
}
}
}
/*
函数功能: 将YUV数据转为RGB格式
函数参数:
unsigned char *yuv_buffer: YUV源数据
unsigned char *rgb_buffer: 转换之后的RGB数据
int iWidth,int iHeight : 图像的宽度和高度
*/
void yuyv_to_rgb(unsigned char *yuv_buffer,unsigned char *rgb_buffer,int iWidth,int iHeight)
{
int x;
int z=0;
unsigned char *ptr = rgb_buffer;
unsigned char *yuyv= yuv_buffer;
for (x = 0; x < iWidth*iHeight; x++)
{
int r, g, b;
int y, u, v;

if (!z)
y = yuyv[0] << 8;
else
y = yuyv[2] << 8;
u = yuyv[1] - 128;
v = yuyv[3] - 128;

r = (y + (359 * v)) >> 8;
g = (y - (88 * u) - (183 * v)) >> 8;
b = (y + (454 * u)) >> 8;

*(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
*(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
*(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);

if(z++)
{
z = 0;
yuyv += 4;
}
}
}

void VideoReadThread_0::slotOnProbeFrame(const QVideoFrame &frame)
{
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
//qDebug()<<"height:"<<cloneFrame.height();
//qDebug()<<"width:"<<cloneFrame.width();
//qDebug()<<"bytesPerLine:"<<cloneFrame.bytesPerLine();
//qDebug()<<"mappedBytes:"<<cloneFrame.mappedBytes();
//qDebug()<<"pixelFormat:"<<cloneFrame.pixelFormat();

unsigned char rgb_buffer[VIDEO_WIDTH*VIDEO_HEIGHT*3];
if(cloneFrame.pixelFormat()==QVideoFrame::Format_NV21)
{
NV21_TO_RGB24(cloneFrame.bits(),rgb_buffer,cloneFrame.width(),cloneFrame.height());
}
else if(cloneFrame.pixelFormat()==QVideoFrame::Format_YUYV)
{
yuyv_to_rgb(cloneFrame.bits(),rgb_buffer,cloneFrame.width(),cloneFrame.height());
}
else
{
qDebug("当前格式编码为%1,暂时不支持转换.\n");
}
cloneFrame.unmap();

//加载图片数据
QImage image(rgb_buffer,
cloneFrame.width(),
cloneFrame.height(),
QImage::Format_RGB888);

//绘制图片水印
QDateTime dateTime(QDateTime::currentDateTime());
//时间效果: 2020-03-05 16:25::04 周一
QString qStr="";
qStr+=dateTime.toString("yyyy-MM-dd hh:mm:ss ddd");
QPainter pp(&image);
QPen pen = QPen(Qt::white);
pp.setPen(pen);
pp.drawText(QPointF(0,20),qStr);

//提取RGB数据
unsigned char *p=rgb_buffer;
for(int i=0;i<image.height();i++)
{
for(int j=0;j<image.width();j++)
{
QRgb rgb=image.pixel(j,i);
*p++=qRed(rgb);
*p++=qGreen(rgb);
*p++=qBlue(rgb);
}
}
emit VideoDataOutput(image); //发送信号
}

//驾驶室:视频刷新显示
void Widget::VideoDataDisplay_0(QImage image)
{
QPixmap my_pixmap;
my_pixmap.convertFromImage(image);
/*在控件上显示*/
ui->label_ImageDisplay_0->setPixmap(my_pixmap);
}

//驾驶室:日志显示
void Widget::Log_Display_0(QString text)
{
Log_Text_Display(ui->plainTextEdit_log_0,text);
}

/*日志显示*/
void Widget::Log_Text_Display(QPlainTextEdit *plainTextEdit_log,QString text)
{
plainTextEdit_log->insertPlainText(text);
//移动滚动条到底部
QScrollBar *scrollbar = plainTextEdit_log->verticalScrollBar();
if(scrollbar)
{
scrollbar->setSliderPosition(scrollbar->maximum());
}
}

//驾驶室:开启所有采集线程
void Widget::Start_VideoAudioEncode_Thread_0()
{
videoRead_Workthread_0->start(); //开启视频采集线程
Init_VideoAudio_WorkClass_0(); //发送初始化信号
}

//驾驶室:退出所有采集线程
void Widget::Stop_VideoAudioEncode_0(bool flag)
{
if(flag==true)
{
Stop_AudioVideo0_work_0(); //发送信号停止摄像头
QThread::msleep(10);
//退出视频采集
videoRead_Workthread_0->quit(); //告诉线程的事件循环以return 0(成功)退出
videoRead_Workthread_0->wait(); //等待线程退出
}
}

void Widget::on_pushButton_update_clicked()
{
UpdateVideoAudiodDevice(ui->comboBox_video_0,ui->plainTextEdit_log_0);
}

/*刷新本机可以的音频设备列表*/
void Widget::UpdateVideoAudiodDevice(
QComboBox *comboBox_video,
QPlainTextEdit *plainTextEdit_log)
{
/*2. 获取摄像头列表*/
video_dev_list.clear();
comboBox_video->clear();
video_dev_list=QCameraInfo::availableCameras();
for(int i=0;i<video_dev_list.size();i++)
{
comboBox_video->addItem(video_dev_list.at(i).deviceName());
}
/*如果没有可用的摄像头设备,按钮不可用*/
if(video_dev_list.size()==0)
{
Log_Text_Display(plainTextEdit_log,"未查询到可用的摄像头设备.\n");
}
}

//停止采集
void Widget::on_pushButton_stop_clicked()
{
Stop_VideoAudioEncode_0(true);
}

void Widget::update()
{
if(ui->label_ImageDisplay_0->pixmap())
opencv_face(ui->label_ImageDisplay_0->pixmap()->toImage());
}

widget.h文件代码:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
//opencv include
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>

#include <QCamera>
#include <QVideoProbe>
#include <QAbstractVideoSurface>
#include <QVideoProbe>
#include <QThread>
#include <QApplication>
#include <QDebug>
#include <QObject>
#include <QMutex>
#include <QMutexLocker>
#include <QWaitCondition>
#include <QQueue>
#include <QCamera>
#include <QPen>
#include <QPainter>
#include <QRgb>
#include <QDateTime>
#include <QCameraInfo>
#include <QPlainTextEdit>
#include <QScrollBar>
#include <QComboBox>
#include <QTimer>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(QWidget *parent = nullptr);
void opencv_face(QImage qImage);
~Widget();
QList<QCameraInfo> video_dev_list;
void show_face(IplImage* img);
class VideoReadThread_0 *videoRead_WorkClass_0; //视频工作类
QThread *videoRead_Workthread_0; //视频线程
/*驾驶室摄像头*/
void Stop_VideoAudioEncode_0(bool flag);//停止线程
void Start_VideoAudioEncode_Thread_0(); //启动线程
void Log_Text_Display(QPlainTextEdit *plainTextEdit_log,QString text);
void UpdateVideoAudiodDevice(QComboBox *comboBox_video, QPlainTextEdit *plainTextEdit_log);
IplImage *QImageToIplImage(const QImage * qImage);
QImage *IplImageToQImage(IplImage *img);
QTimer timer;
signals:
void Init_VideoAudio_WorkClass_0();
void Stop_AudioVideo0_work_0();
private slots:
void update();
void on_pushButton_Start_clicked();
void Log_Display_0(QString text);
void VideoDataDisplay_0(QImage );
void on_pushButton_update_clicked();

void on_pushButton_stop_clicked();

private:
Ui::Widget *ui;
};

class VideoReadThread_0:public QObject
{
Q_OBJECT
public:
QCamera *camera;
QVideoProbe *m_pProbe;
VideoReadThread_0(QObject* parent=nullptr):QObject(parent){camera=nullptr;m_pProbe=nullptr;}
~VideoReadThread_0();
void Camear_Init(void);
public slots:
void stop();
void run();
void slotOnProbeFrame(const QVideoFrame &frame);
signals:
void VideoDataOutput(QImage); //输出信号
};
//视频音频编码类
class VideoAudioEncode
{
public:
QCameraInfo camera; //当前选择的摄像头
};
//视频输出尺寸
#define VIDEO_WIDTH 640
#define VIDEO_HEIGHT 480
extern class VideoAudioEncode videoaudioencode_0;
#endif // WIDGET_H

main.cpp文件代码:

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}

UI界面文件:

 

进群领取qt开发学习资料以及技术交流  在下方↓↓↓↓↓↓↓↓

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hw5230/article/details/130650045

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法