下面的程序?qū)崿F(xiàn)了視頻的旋轉(zhuǎn)及縮放,窗口中點(diǎn)擊鼠標(biāo)左鍵視頻向左旋轉(zhuǎn),點(diǎn)擊鼠標(biāo)右鍵視頻向右旋轉(zhuǎn)并且視頻縮小了二分之一。程序中首先把yvyv422轉(zhuǎn)換成了RGB24,然后利用opencv進(jìn)行了旋轉(zhuǎn)和縮放,其后用sdl2進(jìn)行了渲染。使用了ffmpeg、sdl2、gtk、opencv四個(gè)開(kāi)源組件,編譯時(shí)請(qǐng)先安裝他們,下面是完整的代碼及編譯命令。
?
//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,
"請(qǐng)輸入攝像頭設(shè)備名稱、窗口尺寸、幀速率");
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
return -1;
}
sscanf(win_size1, "%dx%d", win_width, win_height);
return 0;
}
//yuv422 轉(zhuǎn) 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 轉(zhuǎn) 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:發(fā)現(xiàn)攝像頭
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("打開(kāi)設(shè)備失敗(%s)\n",camera_devices_name);
close(fd);
continue;
}
close(fd);
sprintf(temp,"發(fā)現(xiàn)攝像頭:%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,"請(qǐng)輸入攝像頭設(shè)備文件名\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("打開(kāi)設(shè)備失敗\n");
return;
}
struct v4l2_fmtdesc v4fmt;
v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //視頻捕獲設(shè)備
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("打開(kāi)設(shè)備失敗");
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("打開(kāi)設(shè)備失敗");
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:視頻預(yù)覽并實(shí)現(xiàn)視頻幀任意角度旋轉(zhuǎn)
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窗口數(shù)據(jù)
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("視頻預(yù)覽"
,SDL_WINDOWPOS_CENTERED
,SDL_WINDOWPOS_CENTERED
,win_width
,win_height
,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if(sdl_window == NULL){
printf("SDL_window創(chuàng)建失敗\n");
return;
}
sdl_renderer = SDL_CreateRenderer(sdl_window
,-1
,SDL_RENDERER_ACCELERATED);
/*dhl:旋轉(zhuǎn)后圖片的寬,高也變了,應(yīng)根據(jù)新的尺寸創(chuàng)建紋理,否則圖片變形
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錯(cuò)誤\n");
return;
}
AVFrame *frame_yuyv422 = av_frame_alloc();
if(!frame_yuyv422){
printf("av_frame_alloc錯(cuò)誤\n");
return;
}
int frame_count = 0; //dhl:記錄獲取的幀數(shù)
SDL_Event event;
int degrees=50; //dhl:旋轉(zhuǎn)角度
while (av_read_frame(pFormatCtx, pkt) >= 0 ) {
if(pkt->stream_index == videoindex){
//dhl:發(fā)送給解碼器
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:轉(zhuǎn)換 yuyv422 到 RGB24
convert_yuv_to_rgb_buffer(buffer_pixels, buffer_rgb, win_width, win_height);
int w_width=win_width;
int h_height=win_height;
//dhl:按指定度數(shù)旋轉(zhuǎn)圖片
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:將紋理數(shù)據(jù)拷貝給渲染器
sdl_rect.x = 0;
sdl_rect.y = 0;
sdl_rect.w = h_height;
sdl_rect.h = w_width;
//dhl:先清空幀畫(huà)面,再重新繪制
SDL_RenderClear(sdl_renderer);
SDL_RenderCopy(sdl_renderer,sdl_texture,NULL,&sdl_rect);
//dhl:顯示幀畫(huà)面
SDL_RenderPresent(sdl_renderer);
//dhl:延時(shí)渲染
//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:按下鼠標(biāo)左鍵向左旋轉(zhuǎn)一度
}
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:按下鼠標(biāo)右鍵向右旋轉(zhuǎn)一度
}
}
av_packet_unref(pkt);
}
sprintf(disp,"預(yù)覽總幀數(shù):%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攝像頭測(cè)試程序(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); //設(shè)置字體大小
labelChild = gtk_bin_get_child(GTK_WIDGET(button1)); //取出GtkButton里的label
gtk_widget_modify_font(GTK_WIDGET(labelChild), font); //設(shè)置label的字體, 這樣這個(gè)GtkButton上面顯示的字體就變了
labelChild = gtk_bin_get_child(GTK_WIDGET(button2));
gtk_widget_modify_font(GTK_WIDGET(labelChild), font);
button3 = gtk_button_new_with_label("視頻預(yù)覽");
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實(shí)現(xiàn)旋轉(zhuǎn)等功能
**/
//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:圖片上下翻轉(zhuǎn)
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 degrees
int left_rotate_image(unsigned char* src_data, unsigned char* des_data,int width, int height)
{
return 0;
}
//dhl:right Rotate 90 degrees
int righht_rotate_image(unsigned char* src_data, unsigned char* des_data,int width, int height)
{
return 0;
}
//dhl:arbitrary degrees rotate
int 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
運(yùn)行效果圖:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-677649.html
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-677649.html
到了這里,關(guān)于Linux系統(tǒng)USB攝像頭測(cè)試程序(四)_視頻旋轉(zhuǎn)及縮放的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!