Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#在图像中获得主色调_C#_Image Processing_Ffmpeg - Fatal编程技术网

C#在图像中获得主色调

C#在图像中获得主色调,c#,image-processing,ffmpeg,C#,Image Processing,Ffmpeg,我正在制作一个程序,从视频中截图。 它从视频中提取帧(使用ffmpeg),然后将它们合并到一个文件中 所有的作品都很好,除了有时我会得到(几乎)黑色的图像,主要是在视频的开头和结尾 我能想到的一个可能的解决方案是检测提取的帧是否暗。如果是暗的,则从稍微不同的时间提取另一帧 如何检测提取的帧是否为暗/黑?或者我还有别的办法解决这个问题吗 private void getScreenshots_Click(object sender, EventArgs e) { int index = 0

我正在制作一个程序,从视频中截图。 它从视频中提取帧(使用ffmpeg),然后将它们合并到一个文件中

所有的作品都很好,除了有时我会得到(几乎)黑色的图像,主要是在视频的开头和结尾

我能想到的一个可能的解决方案是检测提取的帧是否暗。如果是暗的,则从稍微不同的时间提取另一帧

如何检测提取的帧是否为暗/黑?或者我还有别的办法解决这个问题吗

private void getScreenshots_Click(object sender, EventArgs e)
{
    int index = 0;
    foreach (string value in this.filesList.Items)
    {
        string file = selectedFiles[index] + "\\" + value;

        // ------------------------------------------------
        //   MediaInfo
        // ------------------------------------------------
        // https://github.com/Nicholi/MediaInfoDotNet
        //
        // get file width, height, and frame count
        //
        // get aspect ratio of the video
        // and calculate height of thumbnail 
        // using width and aspect ratio
        //
        MediaInfo MI = new MediaInfo();
        MI.Open(file);
        var width = MI.Get(StreamKind.Video, 0, "Width");
        var height = MI.Get(StreamKind.Video, 0, "Height");
        decimal d = Decimal.Parse(MI.Get(StreamKind.Video, 0, "Duration"));
        decimal frameCount = Decimal.Parse(MI.Get(StreamKind.Video, 0, "FrameCount"));
        MI.Close();
        decimal ratio = Decimal.Divide(Decimal.Parse(width), Decimal.Parse(height));
        int newHeight = Decimal.ToInt32(Decimal.Divide(newWidth, ratio));
        decimal startTime = Decimal.Divide(d, totalImages);
        //totalImages - number of thumbnails the final image will have
        for (int x = 0; x < totalImages; x++)
        {
            // increase the time where the thumbnail is taken on each iteration
            decimal newTime = Decimal.Multiply(startTime, x);
            string time = TimeSpan.FromMilliseconds(double.Parse(newTime.ToString())).ToString(@"hh\:mm\:ss");

            string outputFile = this.tmpPath + "img-" + index + x + ".jpg";

            // create individual thumbnails with ffmpeg
            proc = new Process();
            proc.StartInfo.FileName = "ffmpeg.exe";
            proc.StartInfo.Arguments = "-y -seek_timestamp 1 -ss " + time + " -i \"" + file + "\" -frames:v 1 -qscale:v 3 \"" + outputFile + "\"";
            proc.Start();
            proc.WaitForExit();
        }

        // set width and height of final image
        int w = (this.cols * newWidth) + (this.spacing * this.cols + this.spacing);
        int h = (this.rows * newHeight) + (this.spacing * this.rows + this.spacing);

        int left, top, i = 0;
        // combine individual thumbnails into one image
        using (Bitmap bmp = new Bitmap(w, h))
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.Clear(this.backgroundColor);
                // this.rows - number of rows
                for (int y = 0; y < this.rows; y++)
                {
                    // put images on a column
                    // this.cols - number of columns
                    // when x = number of columns go to next row
                    for (int x = 0; x < this.cols; x++)
                    {
                        Image imgFromFile = Image.FromFile(this.tmpPath + "img-" + index + i + ".jpg");
                        MemoryStream imgFromStream = new MemoryStream();
                        imgFromFile.Save(imgFromStream, imgFromFile.RawFormat);
                        imgFromFile.Dispose();

                        left = (x * newWidth) + ((x + 1) * this.spacing);
                        top = (this.spacing * (y + 1)) + (newHeight * y);
                        g.DrawImage(Image.FromStream(imgFromStream), left, top, newWidth, newHeight);
                        i++;
                    }
                }
            }

            // save the final image
            bmp.Save(selectedFiles[index] + "\\" + value + ".jpg");
        }
        index++;
    }
}
private void getScreenshots\u单击(对象发送者,事件参数e)
{
int指数=0;
foreach(this.filesList.Items中的字符串值)
{
字符串文件=所选文件[索引]+“\\\”+值;
// ------------------------------------------------
//媒体信息
// ------------------------------------------------
// https://github.com/Nicholi/MediaInfoDotNet
//
//获取文件宽度、高度和帧数
//
//获取视频的纵横比
//并计算缩略图的高度
//使用宽度和纵横比
//
MediaInfo MI=新的MediaInfo();
MI.打开(文件);
var width=MI.Get(StreamKind.Video,0,“宽度”);
var height=MI.Get(StreamKind.Video,0,“height”);
decimald=decimal.Parse(MI.Get(StreamKind.Video,0,“Duration”);
decimal frameCount=decimal.Parse(MI.Get(StreamKind.Video,0,“frameCount”);
MI.Close();
十进制比率=十进制.除法(decimal.Parse(宽度),decimal.Parse(高度));
int newHeight=Decimal.ToInt32(Decimal.Divide(newWidth,ratio));
十进制开始时间=十进制除法(d,totalImages);
//totalImages-最终图像的缩略图数量
对于(int x=0;x
您需要分析各个帧。循环遍历每个帧/图像的像素并计算整体亮度

这实际上是在关于确定图像整体亮度的一篇文章中概述的。你可以把同样的想法应用到你的需要上

根据您希望如何实现这一点,它可能会相当繁重。如果需要动态执行此操作,您很可能希望将帧分析缩小到较小的部分,而不是整个图像。但是,如果您这样做更多的是作为一种后处理技术,那么它可能没有那么重要。

多亏了我设法解决了我的问题(希望如此)

以下是方法:

  • 我把这本书包括在课堂上
  • 我添加了一个函数,用于获取图像并将其转换为位图,找到
  • 我将创建缩略图的代码移到了它自己的函数中

    private void ffmpegGetThumb(string input, string output, double time, int getNewFrame = 0)
    {
        // create individual thumbnails with ffmpeg
        string timeString = TimeSpan.FromMilliseconds(time).ToString(@"hh\:mm\:ss");
        proc = new Process();
        proc.StartInfo.FileName = "ffmpeg.exe";
        proc.StartInfo.Arguments = "-y -seek_timestamp 1 -ss " + timeString + " -i \"" + input + "\" -frames:v 1 -qscale:v 3 \"" + output + "\"";
        proc.Start();
        proc.WaitForExit();
    }
    
  • 我创建了一个函数,可以将缩略图转换为位图,检查其亮度,并根据需要调整拍摄缩略图的时间

    private void brightThumb(string input, string output, double time, int getNewFrame, bool goBack)
    {
        //get initial thumbnail
        this.ffmpegGetThumb(input, output, time);
        Bitmap frame = this.ConvertToBitmap(output);
        double brightness = CalculateAverageLightness(frame);
        double newTime = time;
    
        if (CalculateAverageLightness(frame) < 0.1)
        {
            // brightness is to low
            // get a new thumbnail by increasing the time at which it's taken
            if (getNewFrame == 1 && goBack == false)
            {
                newTime = time + 1000;
            }
            // if goBack is true (the time is beyond 75% of the total duration)
            // we decrease the time (if curent time is at credits no point going forward)
            else if (getNewFrame == 1 && goBack == true)
            {
                newTime = time - 1000;
            }
            // take a new thumbnail at the adujted time
            this.brightThumb(input, output, newTime, 1, goBack);
        }
    }
    
  • 在性能方面,与执行此检查之前相比,我认为执行时间没有大的变化。如果它发现许多暗图像,那么它将重新获取它们,因此这将明显增加执行时间


    我能想到一个问题。如果视频以足够长的黑色场景结束,并包含2个缩略图。在这种情况下,缩略图将是相同的,因为它将返回一秒钟,直到找到足够明亮的图像。

    @CK13很棒。如果这回答了你的问题,你能接受这个作为结束问题的答案吗?谢谢
    bool goBack = false;
    if (x > (totalImages/4) * 3)
    {
        goBack = true;
    }
    this.brightThumb(file, outputFile, time, 0, goBack);