Linux系统USB摄像头测试程序(四)_视频旋转及缩放
下面的程序实现了视频的旋转及缩放,窗口中点击鼠标左键视频向左旋转,点击鼠标右键视频向右旋转并且视频缩小了二分之一。程序中首先把yvyv422转换成了RGB24,然后利用opencv进行了旋转和缩放,其后用sdl2进行了渲染。使用了ffmpeg、sdl2、gtk、opencv四个开源组件,编译时请先安装他们,下面是完整的代码及编译命令。
//rotate_camera.c
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <zconf.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gtk-3.0/gtk/gtk.h>
#include <gdk/gdkx.h>#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavutil/imgutils.h"
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/buffersink.h>#include <SDL2/SDL.h>//dhl:gtk窗口组件
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *button1,*button2,*button3;
GtkWidget *text,*text1,*text2,*text3;
GtkTextBuffer *buffer,*buffer1,*buffer2,*buffer3;
GtkWidget *label1,*label2,*label3,*label_line;//dhl:sdl窗口组件
SDL_Window *sdl_window;
SDL_Renderer *sdl_renderer;
SDL_Texture *sdl_texture;//dhl:消息缓存
char disp[2048]={0};
char temp[128]={0};//dhl:获取窗口控件的值
int getWHR(char *device_name,char *win_size,int *win_width,int *win_height, char *frame_rate_t)
{GtkTextIter start,end;gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buffer1),&start,&end);GtkTextIter s=start,e=end;sprintf(device_name,"%s",gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer1),&s,&e,FALSE));gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buffer2),&start,&end);s=start,e=end;gchar *win_size1 = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer2),&s,&e,FALSE);sprintf(win_size,"%s",gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer2),&s,&e,FALSE));gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buffer3),&start,&end);s=start,e=end;sprintf(frame_rate_t,"%s",gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer3),&s,&e,FALSE));if (!strcmp(device_name,"")|| !strcmp(win_size,"")||!strcmp(frame_rate_t,"")) {GtkWidget * dialog= dialog = gtk_message_dialog_new (NULL,GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_INFO,GTK_BUTTONS_CLOSE,"请输入摄像头设备名称、窗口尺寸、帧速率");gtk_dialog_run (GTK_DIALOG (dialog));gtk_widget_destroy (dialog);return -1;}sscanf(win_size1, "%dx%d", win_width, win_height);return 0;
}//yuv422 转 RGB24(subfunction)
int convert_yuv_to_rgb_pixel(int y, int u, int v)
{unsigned int pixel32 = 0;unsigned char *pixel = (unsigned char *)&pixel32;int r, g, b;r = y + (1.370705 * (v-128));g = y - (0.698001 * (v-128)) - (0.337633 * (u-128));b = y + (1.732446 * (u-128));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;pixel[0] = r ;pixel[1] = g ;pixel[2] = b ;return pixel32;
}//yuv422 转 RGB24
int convert_yuv_to_rgb_buffer(unsigned char *yuv, unsigned char *rgb, unsigned int width, unsigned int height)
{unsigned int in, out = 0;unsigned int pixel_16;unsigned char pixel_24[3];unsigned int pixel32;int y0, u, y1, v;for(in = 0; in < width * height * 2; in += 4){pixel_16 = yuv[in + 3] << 24 |yuv[in + 2] << 16 |yuv[in + 1] << 8 |yuv[in + 0];y0 = (pixel_16 & 0x000000ff);u = (pixel_16 & 0x0000ff00) >> 8;y1 = (pixel_16 & 0x00ff0000) >> 16;v = (pixel_16 & 0xff000000) >> 24;pixel32 = convert_yuv_to_rgb_pixel(y0, u, v);pixel_24[0] = (pixel32 & 0x000000ff);pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;rgb[out++] = pixel_24[0];rgb[out++] = pixel_24[1];rgb[out++] = pixel_24[2];pixel32 = convert_yuv_to_rgb_pixel(y1, u, v);pixel_24[0] = (pixel32 & 0x000000ff);pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;rgb[out++] = pixel_24[0];rgb[out++] = pixel_24[1];rgb[out++] = pixel_24[2];}return 0;}//dhl:发现摄像头
void button1_clicked(GtkWidget *widget, gpointer data)
{char camera_devices_name[128]={0};for (int loop=0;loop<10;loop++) {sprintf(camera_devices_name,"/dev/video%d",loop);int fd = open(camera_devices_name, O_RDWR);if(fd < 0){printf("打开设备失败(%s)\n",camera_devices_name);close(fd);continue;}close(fd);sprintf(temp,"发现摄像头:%s\n",camera_devices_name);strcat(disp,temp);gtk_text_buffer_set_text(buffer,disp,-1);}sprintf(disp,"%s","");
}//dhl:查询配置信息
void button2_clicked(GtkWidget *widget, gpointer data)
{int line_num=0;gchar *device_name;GtkTextIter start,end;gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buffer1),&start,&end);const GtkTextIter s=start,e=end;device_name=gtk_text_buffer_get_text(GTK_TEXT_BUFFER(buffer1),&s,&e,FALSE);if (!strcmp(device_name,"")){sprintf(temp,"请输入摄像头设备文件名\n");strcat(disp,temp);gtk_text_buffer_set_text(buffer,disp,-1);sprintf(disp,"%s","");return;}//dhl:查询摄像头支持的视频格式int fd = open(device_name, O_RDWR);if(fd < 0){printf("打开设备失败\n");return;}struct v4l2_fmtdesc v4fmt;v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //视频捕获设备int i=0;while(1){v4fmt.index = i++;int ret = ioctl(fd, VIDIOC_ENUM_FMT, &v4fmt);if(ret < 0){printf("获取摄像头格式失败");break;}printf("index=%d\n", v4fmt.index);printf("flags=%d\n", v4fmt.flags);printf("description=%s\n", v4fmt.description);unsigned char *p = (unsigned char *)&v4fmt.pixelformat;printf("pixelformat=%c%c%c%c\n", p[0],p[1],p[2],p[3]);printf("reserved=%d\n", v4fmt.reserved[0]);sprintf(temp,"摄像头支持的视频格式(%d)\n",i);strcat(disp,temp);sprintf(temp,"index=%d,", v4fmt.index);strcat(disp,temp);sprintf(temp,"flags=%d,", v4fmt.flags);strcat(disp,temp);sprintf(temp,"description=%s,", v4fmt.description);strcat(disp,temp);sprintf(temp,"pixelformat=%c%c%c%c,", p[0],p[1],p[2],p[3]);strcat(disp,temp);sprintf(temp,"reserved=%d\n", v4fmt.reserved[0]);strcat(disp,temp);}close(fd);//dhl:MJPG支持的所有分辨率如下fd = open(device_name, O_RDWR);if(fd < 0){perror("打开设备失败");return;}struct v4l2_frmsizeenum frmsize;frmsize.index = 0;frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;printf("MJPEG格式支持所有分辨率如下:\n");//frmsize.pixel_format = V4L2_PIX_FMT_YUYV;frmsize.pixel_format = V4L2_PIX_FMT_MJPEG;sprintf(temp,"MJPG支持的分辨率:\n");strcat(disp,temp);line_num=1;while(ioctl(fd,VIDIOC_ENUM_FRAMESIZES,&frmsize) == 0){printf("frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);frmsize.index++;if ((line_num % 5) != 0) { sprintf(temp,"MJPEG frame_size<%d*%d>, ",frmsize.discrete.width,frmsize.discrete.height);}else {sprintf(temp,"MJPEG frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);}strcat(disp,temp);line_num++;if (line_num == 6) {line_num = 1;}}close(fd);sprintf(temp,"%s","\n");strcat(disp,temp);//dhl:YUV支持所有分辨率如下fd = open(device_name, O_RDWR);if(fd < 0){perror("打开设备失败");return;}//struct v4l2_frmsizeenum frmsize;frmsize.index = 0;frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;printf("MJPEG格式支持所有分辨率如下:\n");frmsize.pixel_format = V4L2_PIX_FMT_YUYV;//frmsize.pixel_format = V4L2_PIX_FMT_MJPEG;sprintf(temp,"YUV支持的分辨率:\n");strcat(disp,temp);line_num = 1;while(ioctl(fd,VIDIOC_ENUM_FRAMESIZES,&frmsize) == 0){printf("frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);frmsize.index++;if ((line_num % 5) != 0) { sprintf(temp,"YUYV frame_size<%d*%d>, ",frmsize.discrete.width,frmsize.discrete.height);}else {sprintf(temp,"YUYV frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);}strcat(disp,temp);line_num++;if (line_num == 6) {line_num = 1;}}close(fd);gtk_text_buffer_set_text(buffer,disp,-1);sprintf(disp,"%s","");}//dhl:视频预览并实现视频帧任意角度旋转
void button3_clicked(GtkWidget *widget, gpointer data)
{AVFormatContext *pFormatCtx;int i, videoindex;AVCodecContext *pCodecCtx;AVCodec *pCodec;int ret = -1;int win_width=0, win_height=0;gchar device_name[128];gchar win_size[128];gchar frame_rate_t[128];//dhl:获取gtk窗口数据int iRet=getWHR(device_name,win_size,&win_width,&win_height, frame_rate_t);if (iRet!=0) {return;}if (SDL_Init(SDL_INIT_VIDEO)) {printf("Could not initialize SDL - %s\n", SDL_GetError());return;}else{printf("initialize SDL ok\n");}sdl_window = SDL_CreateWindow("视频预览",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,win_width,win_height,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);if(sdl_window == NULL){printf("SDL_window创建失败\n");return;}sdl_renderer = SDL_CreateRenderer(sdl_window,-1,SDL_RENDERER_ACCELERATED);/*dhl:旋转后图片的宽,高也变了,应根据新的尺寸创建纹理,否则图片变形sdl_texture = SDL_CreateTexture(sdl_renderer//,SDL_PIXELFORMAT_IYUV//,SDL_PIXELFORMAT_YUY2,SDL_PIXELFORMAT_RGB24,SDL_TEXTUREACCESS_TARGET,win_width,win_height);*/sdl_texture = SDL_CreateTexture(sdl_renderer//,SDL_PIXELFORMAT_IYUV//,SDL_PIXELFORMAT_YUY2,SDL_PIXELFORMAT_RGB24,SDL_TEXTUREACCESS_TARGET,390,400);SDL_Rect sdl_rect;char *buffer_pixels = malloc(win_width*win_height*4);char *buffer_rgb = malloc(win_width*win_height*3);char *buffer_rgb_reversal = malloc(win_width*win_height*3);pFormatCtx = avformat_alloc_context();const AVInputFormat *ifmt = av_find_input_format("v4l2");AVDictionary *option =NULL;av_dict_set(&option,"video_size",win_size,0);av_dict_set(&option,"framerate",frame_rate_t,0);//av_dict_set(&option,"pixel_format","yuv420p12be",0); //指定格式avformat_open_input(&pFormatCtx, device_name, ifmt,&option);if(avformat_find_stream_info(pFormatCtx, NULL) < 0){printf("Couldn't find stream information.\n");return;}videoindex = -1;for(i = 0; i < pFormatCtx->nb_streams; i++){if(pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){videoindex = i;break;}}if(videoindex == -1){printf("Didn't find a video stream.\n");return;}else{printf("Find a video stream:%d.\n", videoindex);}pCodec = (AVCodec*)avcodec_find_decoder(pFormatCtx->streams[videoindex]->codecpar->codec_id);if(pCodec == NULL){printf("Codec not found.\n");return;}pCodecCtx = avcodec_alloc_context3(pCodec);avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoindex]->codecpar);printf("VideoStream:Frame.Width=%d,Height=%d\n",pCodecCtx->width, pCodecCtx->height);if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0){printf("Could not open codec.\n");return;}AVPacket *pkt = av_packet_alloc();if(!pkt){printf("av_packet_alloc错误\n");return;}AVFrame *frame_yuyv422 = av_frame_alloc();if(!frame_yuyv422){printf("av_frame_alloc错误\n");return;}int frame_count = 0; //dhl:记录获取的帧数SDL_Event event;int degrees=50; //dhl:旋转角度while (av_read_frame(pFormatCtx, pkt) >= 0 ) {if(pkt->stream_index == videoindex){//dhl:发送给解码器if(avcodec_send_packet(pCodecCtx,pkt) != 0){printf("avcodec_send_packet error ...\n");break;}//dhl:从解码器中得到摄像头的原始视频帧int loop=0;while(avcodec_receive_frame(pCodecCtx,frame_yuyv422) == 0){frame_count++;for(int i = 0;i < frame_yuyv422->height;i++){memcpy(buffer_pixels+i * frame_yuyv422->linesize[0],frame_yuyv422->data[0] + i * frame_yuyv422->linesize[0],frame_yuyv422->linesize[0]);}//dhl:转换 yuyv422 到 RGB24convert_yuv_to_rgb_buffer(buffer_pixels, buffer_rgb, win_width, win_height);int w_width=win_width;int h_height=win_height;//dhl:按指定度数旋转图片any_rotate_degrees(buffer_rgb, buffer_pixels,&w_width, &h_height,degrees); //SDL_UpdateTexture(sdl_texture,NULL,buffer_pixels,win_width*2);SDL_UpdateTexture(sdl_texture,NULL,buffer_pixels,h_height*3);//dhl:将纹理数据拷贝给渲染器sdl_rect.x = 0;sdl_rect.y = 0;sdl_rect.w = h_height;sdl_rect.h = w_width;//dhl:先清空帧画面,再重新绘制SDL_RenderClear(sdl_renderer);SDL_RenderCopy(sdl_renderer,sdl_texture,NULL,&sdl_rect);//dhl:显示帧画面SDL_RenderPresent(sdl_renderer);//dhl:延时渲染//SDL_Delay(frame_rate);}}av_packet_unref(pkt);for (int ll=0;ll<10;ll++) {SDL_PollEvent(&event);} if (event.type == SDL_QUIT) {break;}else if (SDL_MOUSEBUTTONDOWN == event.type) {if(SDL_BUTTON_LEFT == event.button.button){int px = event.button.x;int py = event.button.y;printf("left x, y %d %d ...............\n", px, py); printf("degrees %d\n",degrees);degrees=degrees+1; //dhl:按下鼠标左键向左旋转一度}else if(SDL_BUTTON_RIGHT == event.button.button){int px = event.button.x;int py = event.button.y;printf("right x, y %d %d ...............\n", px, py);printf("degrees %d\n",degrees);degrees=degrees-1; //dhl:按下鼠标右键向右旋转一度}} av_packet_unref(pkt); }sprintf(disp,"预览总帧数:%d",frame_count);gtk_text_buffer_set_text(buffer,disp,-1);sprintf(disp,"%s","");av_free(frame_yuyv422);av_packet_free(&pkt);avformat_close_input(&pFormatCtx);free(buffer_pixels);free(buffer_rgb);free(buffer_rgb_reversal);SDL_DestroyTexture(sdl_texture);SDL_DestroyRenderer(sdl_renderer);SDL_DestroyWindow(sdl_window ); SDL_Quit();return;
}int main(int argc,char *argv[])
{gtk_init(&argc,&argv);avdevice_register_all();window = gtk_window_new(GTK_WINDOW_TOPLEVEL);gtk_window_set_title(GTK_WINDOW(window),"USB摄像头测试程序(v1.0.20230728)");//gtk_window_set_resizable(GTK_WINDOW(window),FALSE);gtk_window_set_default_size(GTK_WINDOW(window),1280,800);gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);fixed = gtk_fixed_new();gtk_container_add(GTK_CONTAINER(window),fixed);text = gtk_text_view_new();buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));gtk_text_buffer_set_text(buffer,"",-1);gtk_fixed_put(GTK_FIXED(fixed),text,20,480);gtk_widget_set_size_request(text,1240,300);button1 = gtk_button_new_with_label("查询摄像头");gtk_fixed_put(GTK_FIXED(fixed),button1,320,14);gtk_widget_set_size_request(button1,100,20);label1 = gtk_label_new("摄像头:");gtk_fixed_put(GTK_FIXED(fixed),label1,440,14);gtk_widget_set_size_request(label1,50,30);text1 = gtk_text_view_new();buffer1=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text1));gtk_text_buffer_set_text(buffer1,"",-1);gtk_fixed_put(GTK_FIXED(fixed),text1,500,16);gtk_widget_set_size_request(text1,100,28);sprintf(disp,"/dev/video0");gtk_text_buffer_set_text(buffer1,disp,-1);button2 = gtk_button_new_with_label("查询配置");gtk_fixed_put(GTK_FIXED(fixed),button2,610,14);gtk_widget_set_size_request(button2,80,35);label2 = gtk_label_new("分辨率:");gtk_fixed_put(GTK_FIXED(fixed),label2,740,18);gtk_widget_set_size_request(label2,50,30);text2 = gtk_text_view_new();buffer2=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text2));gtk_text_buffer_set_text(buffer2,"",-1);gtk_fixed_put(GTK_FIXED(fixed),text2,800,16);gtk_widget_set_size_request(text2,100,28);sprintf(disp,"640x480");gtk_text_buffer_set_text(buffer2,disp,-1);label3 = gtk_label_new("帧率:");gtk_fixed_put(GTK_FIXED(fixed),label3,930,18);gtk_widget_set_size_request(label3,50,30);text3 = gtk_text_view_new();buffer3=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text3));gtk_text_buffer_set_text(buffer3,"",-1);gtk_fixed_put(GTK_FIXED(fixed),text3,980,16);gtk_widget_set_size_request(text3,100,28);sprintf(disp,"30");gtk_text_buffer_set_text(buffer3,disp,-1);label_line = gtk_label_new("______________________________________________________________________________________________________________________________");gtk_fixed_put(GTK_FIXED(fixed),label_line,320,45);gtk_widget_set_size_request(label_line,800,3);GtkWidget *labelChild;PangoFontDescription *font;int fontSize = 10;font = pango_font_description_from_string("Sans"); //"Sans"字体名pango_font_description_set_size(font, fontSize * PANGO_SCALE); //设置字体大小labelChild = gtk_bin_get_child(GTK_WIDGET(button1)); //取出GtkButton里的labelgtk_widget_modify_font(GTK_WIDGET(labelChild), font); //设置label的字体, 这样这个GtkButton上面显示的字体就变了labelChild = gtk_bin_get_child(GTK_WIDGET(button2)); gtk_widget_modify_font(GTK_WIDGET(labelChild), font); button3 = gtk_button_new_with_label("视频预览");gtk_fixed_put(GTK_FIXED(fixed),button3,320,80);gtk_widget_set_size_request(button3,80,20);g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);g_signal_connect(G_OBJECT(button1), "clicked", G_CALLBACK(button1_clicked),NULL);g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(button2_clicked),NULL);g_signal_connect(G_OBJECT(button3), "clicked", G_CALLBACK(button3_clicked),NULL); gtk_widget_show_all(window);gtk_main();return 0;
}//edit_image.cpp
#include <opencv2/opencv.hpp>
#include<iostream>
#include<math.h>using namespace cv;
using namespace std;/*** dhl:图片编辑模块,利用opencv4实现旋转等功能**///dhl:any Rotate degrees
int any_rotate(unsigned char* src_data, unsigned char* des_data,int *width, int *height,int degrees)
{int w_wight=*width;int h_height=*height;Mat dst_mat(h_height,w_wight,CV_8UC3);Mat des,m;memcpy(dst_mat.data, src_data ,w_wight*h_height*3*sizeof(unsigned char));Point2f center = Point(dst_mat.cols / 2, dst_mat.rows / 2);double angle = degrees,scale=0.5;int w = dst_mat.cols, h = dst_mat.rows;int bound_w = (h * fabs(sin(angle * CV_PI / 180)) + w * fabs(cos(angle * CV_PI / 180))) * scale;int bound_h = (h * fabs(cos(angle * CV_PI / 180)) + w * fabs(sin(angle * CV_PI / 180))) * scale;m = getRotationMatrix2D(center, angle, scale);m.at<double>(0, 2) += (bound_w - dst_mat.cols) / 2;m.at<double>(1, 2) += (bound_h - dst_mat.rows) / 2;warpAffine(dst_mat,des,m,Size2i(bound_h,bound_w));memcpy(des_data, des.data ,bound_h*bound_w*3);*width=bound_w;*height=bound_h;return 0;
}extern "C" {//dhl:图片上下翻转int reversal_image(unsigned char* src_data, unsigned char* des_data,int data_len){for (int i=0;i<data_len;i++) {des_data[i]=src_data[data_len-i-1];}return 0;}//dhl:left Rotate 90 degreesint left_rotate_image(unsigned char* src_data, unsigned char* des_data,int width, int height){return 0;}//dhl:right Rotate 90 degreesint righht_rotate_image(unsigned char* src_data, unsigned char* des_data,int width, int height){return 0;}//dhl:arbitrary degrees rotateint any_rotate_degrees(unsigned char* src_data, unsigned char* des_data,int *width, int *height,int degrees){any_rotate(src_data, des_data,width, height,degrees);return 0;}}
编译命令:gcc rotate_camera.c edit_image.cpp -o camera_rotate `pkg-config --cflags --libs libavdevice libavfilter libavformat libavcodec libavutil libpostproc libswresample libswscale` `pkg-config --cflags --libs sdl2` `pkg-config --cflags --libs gtk+-3.0` `pkg-config --cflags --libs opencv4` -std=c++11 -lstdc++ -lpthread -lm -w
运行效果图:
相关文章:
Linux系统USB摄像头测试程序(四)_视频旋转及缩放
下面的程序实现了视频的旋转及缩放,窗口中点击鼠标左键视频向左旋转,点击鼠标右键视频向右旋转并且视频缩小了二分之一。程序中首先把yvyv422转换成了RGB24,然后利用opencv进行了旋转和缩放,其后用sdl2进行了渲染。使用了ffmpeg、…...
大模型+学习机,是概念游戏还是双向奔赴?
众所周知,2023年上半年大模型概念炙手可热。各大科技公司纷纷卷入,或宣称布局相关领域,或率先官宣自研大模型。而随着资本市场对大模型概念的热情有所消退,属于这片战场的新一轮角逐慢慢聚焦在了技术的落地应用上。 8月15日&#…...
linux怎么查看用户属于哪个组
查看当前用户所属组 shell> groups root查看指定用户所属组 shell> groups testuser testuser : testusershell> id testuser uid1000(testuser) gid1000(testuser) groups1000(testuser)查看组文件 shell> cat /etc/group...
邂逅JavaScript
前言:前端三大核心 前端开发最主要需要掌握的是三个知识点:HTML、CSS、JavaScript 一、认识编程语言 1.计算机语言 前面我们已经学习了HTML和CSS很多相关的知识: 在之前我们提到过, HTML是一种标记语言, CSS也是一种样式语言; 他们本身都是属于计算…...
Android 中 Fragment判空
1. 判断 Fragment 是否已经被添加到 Activity 中,可以通过 Fragment 的 isAdded() 方法来判断。 2. 判断 Fragment 的 View 是否已经被创建,可以通过 Fragment 的 getView() 方法来判断。 3. 判断 Fragment 是否已经被销毁,可以通过 Fragme…...
软考高级系统架构设计师系列论文八十八:财务数据仓库系统的设计与实现
软考高级系统架构设计师系列论文八十八:财务数据仓库系统的设计与实现 一、摘要二、正文三、总结一、摘要 近年来,数据仓库技术在信息系统的建设中得到了广泛应用,有效地为决策提供了支持。2020年6月,本人所在单位组织开发了财务管理决策系统,该系统主要是使高层领导掌握企…...
fastdeploy部署多线程/进程paddle ocr(python flask框架 )
部署参考:https://github.com/PaddlePaddle/FastDeploy/blob/develop/tutorials/multi_thread/python/pipeline/README_CN.md 安装 cpu: pip install fastdeploy-python gpu :pip install fastdeploy-gpu-python #下载部署示例代码 git cl…...
【图论】拓扑排序
一.定义 拓扑排序是一种对有向无环图(DAG)进行排序的算法,使得图中的每个顶点在排序中都位于其依赖的顶点之后。它通常用于表示一些任务之间的依赖关系,例如在一个项目中,某些任务必须在其他任务之前完成。 拓扑排序的…...
自动化备份方案
背景说明 网上有很多教程,写的都是从零搭建一个什么什么,基本上都是从无到有的教程,但是,很少有文章提及搭建好之后如何备份,这次通过请教GitHub Copilot Chat,生成几个备份脚本,以备后用。 注…...
win11出现安全中心空白和IT管理员已限制对此应用的某些区域的访问
问题 windows安全中心服务被禁用 winr 输入services.msc 找到windows安全中心服务查看是否被禁用,改为启动,不可以改动看第三条 打开设置,找到应用—windows安全中心–终止–修复–重置 重启如果还是不行看第四条 家庭版系统需要打开gped…...
github实用指令(实验室打工人入门必备)
博主进入实验室啦,作为一只手残党决定在这里分享一些常用的github使用情景和操作指南来解救其他手残党。 内容随着情景增加实时更新。如果只有没几个内容说明场景不多(相信对手残党而言是再好不过的消息) 情景一:…...
6. 激活层
6.1 非线性激活 ① inplace为原地替换,若为True,则变量的值被替换。若为False,则会创建一个新变量,将函数处理后的值赋值给新变量,原始变量的值没有修改。 import torch from torch import nn from torch.nn import …...
AIGC ChatGPT 制作地图可视化分析
地图可视化分析是一种将数据通过地图的形式进行展示的方法,可以让人们更加直观、快速、准确的理解和分析数据。以下是地图可视化分析的一些主要好处: 加强数据理解:地图可视化可以将抽象的数字转化为直观的图形,帮助我们更好地理解复杂的数据集。 揭示地理模式:地理位置是…...
2023-08-24 LeetCode每日一题(统计参与通信的服务器)
2023-08-24每日一题 一、题目编号 1267. 统计参与通信的服务器二、题目链接 点击跳转到题目位置 三、题目描述 这里有一幅服务器分布图,服务器的位置标识在 m * n 的整数矩阵网格 grid 中,1 表示单元格上有服务器,0 表示没有。 如果两台…...
前端实习day35
今天是下早班的一天,下完班直接赶车回广州了,吐槽一下深圳站管理得真得差,候车厅小,人巨多,而且进站口的标识也很少,绕了好久才找到!下次再也不去了。 今天是改bug的一天,但是有半天…...
Linux安装jupyter notebook
1. Linux安装jupyter notebook 1.1 生成配置文件 这里在conda环境中安装。 jupyter notebook --generate-config --allow-root上面命令是生成配置文件,并且允许使用root用户运行。配置文件默认生成到~/.jupyter/jupyter_notebook_config.py。 具体解释如下&…...
【猿灰灰赠书活动 - 03期】- 【RHCSA/RHCE 红帽Linux认证学习指南(第7版) EX200 EX300】
说明:博文为大家争取福利,与清华大学出版社合作进行送书活动 图书:《RHCSA/RHCE 红帽Linux认证学习指南(第7版) EX200 & EX300》 一、好书推荐 图书介绍 《RHCSA/RHCE 红帽Linux认证学习指南(第7版) EX200 & E…...
当 Tubi 遇到 Ruby
有人说 Tubi 作为 RubyConf China 金牌赞助商,明明用极具吸引力的 Elixir 后端工程师岗位和高品质的 Elixir Meetup,“拐走了”一批又一批 Rubyist 投身于 Elixir 开发中,却依然让人想在 Tubi 展台前多停留一会儿。 为什么工程师、校友甚至 …...
【C++从0到王者】第二十四站:多态的底层原理
文章目录 前言一、虚函数表二、一道经典的例题三、深度剖析多态的条件之一:为什么必须是父类的指针或引用四、深度剖析多态的条件之二:为什么是虚函数的重写/覆盖?五、虚函数表的一些总结六、关于Func3的验证七、动态绑定与静态绑定八、总结 …...
Java从入门到精通24==》数据库、SQL基本语句、DDL语句
Java从入门到精通24》数据库、SQL基本语句、DDL语句 2023.8.27 文章目录 <center>Java从入门到精通24》数据库、SQL基本语句、DDL语句一、什么是数据库二、数据库的优缺点1、使用数据库的优点:2、使用数据库的缺点: 三、MySQL基本语句四、DDL语句 …...
学习ts(十)装饰器
定义 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上,是一种在不改变原类和使用继承的情况下,动态的扩展对象功能。 装饰器使用expression形式,其中expression必须…...
如何在 Opera 中启用DNS over HTTPS
DNS over HTTPS(基于HTTPS的DNS)是一种更安全的浏览方式,但大多数 Web 浏览器默认情况下不启用它。了解如何在 Opera 浏览器中启用该功能。 您可能不知道这一点,但您的网络浏览器并不像您希望的那样私密或安全。您会看到ÿ…...
STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块
今日学习一下这款AHT10 温湿度传感器模块,给我的OLED手环添加上测温湿度的功能。 文章提供源码、测试工程下载、测试效果图。 目录 AHT10温湿度传感器: 特性: 连接方式: 适用场所范围: 程序设计: 设…...
QT基础使用:组件和代码关联(信号和槽)
自动关联 ui文件在设计环境下,能看到的组件可以使用鼠标右键选择“转到槽”就是开始组件和动作关联。 在自动关联这个过程中软件自动动作的部分 需要对前面头文件进行保存,才能使得声明的函数能够使用。为了方便,自动关联时先对所有文件…...
TCP最大连接数问题总结
最大TCP连接数量限制有:可用端口号数量、文件描述符数量、线程、内存、CPU等。每个TCP连接都需要以下资源,如图所示: 1、可用端口号限制 Q:一台主机可以有多少端口号?端口号与TCP连接?是否能修改&#x…...
【Docker】云原生利用Docker确保环境安全、部署的安全性、安全问题的主要表现和新兴技术产生
前言 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 云原生利用Docker确保环境安全、部署的…...
explain各个字段代表的意思
id:联表查询是每个表的读取顺序,数字越大越先被读取。相同就需要通过table字段判断select_type:查询类型或者是其他操作类型(PRIMARY、UNION、UNION RESULT等)table:正在访问哪个表partitions:匹…...
【已解决】Windows10 pip安装报错:UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0x98
环境:win10, Python3.9 在Pycharm安装YoloV5的依赖包时出现报错:UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0x98 出现 ‘gbk’ codec can’t decode… 的报错一般是因为读取文件出现编码问题导致没法读取文件,因此可以在报错…...
goland 中的调试器 -- Evaluate
今天一个好朋友 找到我,问我关于goland中Evaluate 小计算器的使用方式,说实话,我在此之前也没用过这个东西,然后我就找一些相关文档,但是这类文档少的可怜,所以我就稍微研究一下,找找材料&#…...
你知道公司内部维基到底有哪些功能吗
维基指的是一种协作工作的平台,也就是开源的编辑系统。员工可以在企业维基里面进行存储、共享和协作之类的操作,将企业内部员工的知识共享聚集在一起。今天looklook将会详细讲讲公司内部维基具体到底有哪些功能,供大家参考。 公司内部维基的功…...
企业网站推广的方法有( )/宁波网站seo哪家好
无论你是初学者还是经验丰富的开发人员,对于你和你的团队来说,提高异常处理的能力可以更好的解决问题。Java中的异常处理并不是一件容易的事,初学者会觉得很难理解,即使是经验丰富的开发人员也可能需要花费几个小时来讨论应该如何…...
金陵热线 网站备案/站长交流平台
使用新浪SAE架构搭建自己的网站。将自己在本地编写的PHP程序上传到SAE上。如果要正常使用需要链接MySQL数据库(如果你的网站使用了MySQL数据库服务)。新浪SAE提供了对PHP访问MySQL的程序支持。所以这个过程要实现起来并不困难。只需要修改用户名和密码。创建完应用后࿰…...
如何做系统集成公司网站/网络营销属于什么专业类型
经过小编多次下图刷怪发现起源冰城的稀有材料道具掉落非常多,特别是神魔晶石、祝福宝石和灵魂宝石掉落极高。缺少这类材料的朋友可以在起源冰城打怪刷材料哦!而恶魔令和天地灵气必须击败高级boss和妖兽才有几率掉落一到两个材料,这两种材料太…...
网站建设收费标准市场/网站统计数据
原创!ngxtop-监控nginx的利器!!! 无论名称还是界面,ngxtop的灵感均源自大名鼎鼎的top命令.ngxtop的功能就是,分析Nginx访问日志文件(以及其他日志文件,比如Apache2日志),并通过类似top的界面,实时显示分析后所得的结果.你可能吹嘘自己的综合监控工具拥有…...
做网站制作/互联网销售包括哪些
原标题:文件上传限制绕过技巧严正声明:本文仅限于技术讨论,严禁用于其他用途。简介文件上传漏洞是web安全中经常利用到的一种漏洞形式。一些web应用程序中允许上传图片,文本或者其他资源到指定的位置,文件上传漏洞就是…...
可以做盗版漫画网站吗/网站制作建设
使用 ThreadPoolExecutor表示一个线程池。Executors类则扮演着线程池工厂的角色,通过Executors可以获取特定功能的线程池Executors工厂创建线程池普通线程池public static ExecutorService newFixedThreadPool(int nThreads)public static ExecutorService newFixe…...