目标是每次从视频文件中提取一帧,然后从图像中制作直方图,然后移动到下一帧。
帧提取和直方图处理是工作正常时,帧已保存为图像在硬盘上。但现在我想做这一切在内存中。
为了提取帧,我使用ffmpeg,因为我认为它足够快:
ffmpeg -r 1 -i MyVid.mp4 -r 1 "$filename%03d.png
现在我在命令提示符窗口中使用ffmpeg。
使用此命令,它将在硬盘上保存超过65000幅图像(帧)。但不是将它们保存在硬盘上,我想知道我是否可以对内存中的每一帧进行直方图操作,而不是将所有65000帧保存到硬盘上。
然后我想找到特定的图像使用直方图和保存到硬盘上这帧。
直方图部分现在也使用来自硬盘而不是来自存储器的文件:
private void btnLoadHistogram_Click(object sender, System.EventArgs e)
{
string[] files = Directory.GetFiles(@"d:\screenshots\", "*.jpg");
for (int i = 0; i < files.Length; i++)
{
sbInfo.Text = "Loading image";
if (pbImage.Image != null)
pbImage.Image.Dispose();
pbImage.Image = Image.FromFile(files[i]);//txtFileName.Text);
Application.DoEvents();
sbInfo.Text = "Computing histogram";
long[] myValues = GetHistogram(new Bitmap(pbImage.Image));
Histogram.DrawHistogram(myValues);
sbInfo.Text = "";
}
}
public long[] GetHistogram(System.Drawing.Bitmap picture)
{
long[] myHistogram = new long[256];
for (int i=0;i<picture.Size.Width;i++)
for (int j=0;j<picture.Size.Height;j++)
{
System.Drawing.Color c = picture.GetPixel(i,j);
long Temp=0;
Temp+=c.R;
Temp+=c.G;
Temp+=c.B;
Temp = (int) Temp/3;
myHistogram[Temp]++;
}
return myHistogram;
}
和控制对象HistogramaDesenat类的代码:
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
namespace Histograma
{
/// <summary>
/// Summary description for HistogramaDesenat.
/// </summary>
public class HistogramaDesenat : System.Windows.Forms.UserControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public HistogramaDesenat()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
// TODO: Add any initialization after the InitializeComponent call
this.Paint += new PaintEventHandler(HistogramaDesenat_Paint);
this.Resize+=new EventHandler(HistogramaDesenat_Resize);
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// HistogramaDesenat
//
this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.Name = "HistogramaDesenat";
this.Size = new System.Drawing.Size(208, 176);
}
#endregion
private void HistogramaDesenat_Paint(object sender, PaintEventArgs e)
{
if (myIsDrawing)
{
Graphics g = e.Graphics;
Pen myPen = new Pen(new SolidBrush(myColor),myXUnit);
//The width of the pen is given by the XUnit for the control.
for (int i=0;i<myValues.Length;i++)
{
//We draw each line
g.DrawLine(myPen,
new PointF(myOffset + (i*myXUnit), this.Height - myOffset),
new PointF(myOffset + (i*myXUnit), this.Height - myOffset - myValues[i] * myYUnit));
//We plot the coresponding index for the maximum value.
if (myValues[i]==myMaxValue)
{
SizeF mySize = g.MeasureString(i.ToString(),myFont);
g.DrawString(i.ToString(),myFont,new SolidBrush(myColor),
new PointF(myOffset + (i*myXUnit) - (mySize.Width/2), this.Height - myFont.Height ),
System.Drawing.StringFormat.GenericDefault);
}
}
//We draw the indexes for 0 and for the length of the array beeing plotted
g.DrawString("0",myFont, new SolidBrush(myColor),new PointF(myOffset,this.Height - myFont.Height),System.Drawing.StringFormat.GenericDefault);
g.DrawString((myValues.Length-1).ToString(),myFont,
new SolidBrush(myColor),
new PointF(myOffset + (myValues.Length * myXUnit) - g.MeasureString((myValues.Length-1).ToString(),myFont).Width,
this.Height - myFont.Height),
System.Drawing.StringFormat.GenericDefault);
//We draw a rectangle surrounding the control.
g.DrawRectangle(new System.Drawing.Pen(new SolidBrush(Color.Black),1),0,0,this.Width-1,this.Height-1);
}
}
long myMaxValue;
private long[] myValues;
private bool myIsDrawing;
private float myYUnit; //this gives the vertical unit used to scale our values
private float myXUnit; //this gives the horizontal unit used to scale our values
private int myOffset = 20; //the offset, in pixels, from the control margins.
private Color myColor = Color.Black;
private Font myFont = new Font("Tahoma",10);
[Category("Histogram Options")]
[Description ("The distance from the margins for the histogram")]
public int Offset
{
set
{
if (value>0)
myOffset= value;
}
get
{
return myOffset;
}
}
[Category("Histogram Options")]
[Description ("The color used within the control")]
public Color DisplayColor
{
set
{
myColor = value;
}
get
{
return myColor;
}
}
/// <summary>
/// We draw the histogram on the control
/// </summary>
/// <param name="myValues">The values beeing draw</param>
public void DrawHistogram(long[] Values)
{
myValues = new long[Values.Length];
Values.CopyTo(myValues,0);
myIsDrawing = true;
myMaxValue = getMaxim(myValues);
ComputeXYUnitValues();
this.Refresh();
}
/// <summary>
/// We get the highest value from the array
/// </summary>
/// <param name="Vals">The array of values in which we look</param>
/// <returns>The maximum value</returns>
private long getMaxim(long[] Vals)
{
if (myIsDrawing)
{
long max = 0;
for (int i=0;i<Vals.Length;i++)
{
if (Vals[i] > max)
max = Vals[i];
}
return max;
}
return 1;
}
private void HistogramaDesenat_Resize(object sender, EventArgs e)
{
if (myIsDrawing)
{
ComputeXYUnitValues();
}
this.Refresh();
}
private void ComputeXYUnitValues()
{
myYUnit = (float) (this.Height - (2 * myOffset)) / myMaxValue;
myXUnit = (float) (this.Width - (2 * myOffset)) / (myValues.Length-1);
}
}
}
所以最后我想做的是:
- 使用FFMPEG从存储器中的视频文件中提取帧。
- 而不是使用Directory.GetFiles,我想对ffmpeg从内存中提取的每一帧进行直方图操作。
- 每个提取的帧图像使用直方图来发现图像中是否存在 lightning (天气 lightning )。
- 如果有 lightning ,则将帧图像保存到硬盘。
1条答案
按热度按时间l7wslrjt1#
对于ffmpeg,请尝试FFmpeg.AutoGen
但是你需要学习ffmpeg api的解复用器和解码器,以获得原始帧。
对于opencv,请尝试emgucv(推荐)
您可以尝试在this之类的地方搜索示例