英文:
Why when creating histogram channels by colors it keep saving the same channel blue color?
问题
以下是代码部分的中文翻译:
// 这是一个有点长但都相关的方法。
private int[] CalculateChannelHistogram(Bitmap image, Color channelColor)
{
int[] histogram = new int[256];
BitmapData imageData = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
unsafe
{
byte* ptr = (byte*)imageData.Scan0;
for (int y = 0; y < imageData.Height; y++)
{
for (int x = 0; x < imageData.Width; x++)
{
byte channelValue = 0;
if (channelColor == Color.Red)
channelValue = ptr[y * imageData.Stride + x * 4 + 2];
else if (channelColor == Color.Green)
channelValue = ptr[y * imageData.Stride + x * 4 + 1];
else if (channelColor == Color.Blue)
channelValue = ptr[y * imageData.Stride + x * 4];
histogram[channelValue]++;
}
}
}
image.UnlockBits(imageData);
return histogram;
}
// 这是按钮点击事件中使用的方法。
private async void btnOpenVideo_Click(object sender, EventArgs e)
{
// 初始化 CancellationTokenSource
cancellationTokenSource = new CancellationTokenSource();
// 初始化直方图列表
histograms = new List<int[]>();
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "Video Files (*.mp4;*.avi;*.mkv)|*.mp4;*.avi;*.mkv|All files (*.*)|*.*";
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string videoPath = openFileDialog.FileName;
// 使用 VideoFileReader 打开视频文件
using (VideoFileReader videoReader = new VideoFileReader())
{
videoReader.Open(videoPath);
// 获取视频中的总帧数
int totalFrames = (int)videoReader.FrameCount;
// 清除图形上的任何现有曲线
zedGraphControl1.GraphPane.CurveList.Clear();
// 设置进度条的最大值
progressBar1.Value = 0;
progressBar1.Maximum = totalFrames;
// 禁用按钮以防止多次提取
btnOpenVideo.Enabled = false;
histograms.Clear();
// 处理视频中的每一帧
await Task.Run(async () =>
{
for (int frameIndex = 0; frameIndex < totalFrames; frameIndex++)
{
// 检查是否请求了取消操作
if (cancellationTokenSource.IsCancellationRequested)
break;
// 读取视频帧
Bitmap frame = videoReader.ReadVideoFrame(frameIndex);
// 计算并显示直方图
int[] grayscaleHistogram = CalculateGrayscaleHistogram(frame);
int[] redHistogram = CalculateChannelHistogram(frame, Color.Red);
int[] greenHistogram = CalculateChannelHistogram(frame, Color.Green);
int[] blueHistogram = CalculateChannelHistogram(frame, Color.Blue);
histograms.Add(grayscaleHistogram);
// 绘制直方图
PlotHistogram(grayscaleHistogram, "Grayscale Histogram", "Pixel Value", "Frequency", zedGraphControl1.GraphPane, Color.Blue);
PlotHistogram(redHistogram, "Red Channel Histogram", "Pixel Value", "Frequency", zedGraphControl1.GraphPane, Color.Red);
PlotHistogram(greenHistogram, "Green Channel Histogram", "Pixel Value", "Frequency", zedGraphControl1.GraphPane, Color.Green);
PlotHistogram(blueHistogram, "Blue Channel Histogram", "Pixel Value", "Frequency", zedGraphControl1.GraphPane, Color.Blue);
// 在帧上绘制直方图信息
DrawHistogramInformation(frame, grayscaleHistogram, "Grayscale Histogram");
// 保存带有直方图的帧
string frameFolder = Path.Combine(outputFolder, $"Frame_{frameIndex}");
if (!Directory.Exists(frameFolder))
{
Directory.CreateDirectory(frameFolder);
}
string frameImagePath = Path.Combine(frameFolder, $"Frame_{frameIndex}.png");
frame.Save(frameImagePath, ImageFormat.Png);
// 将直方图值保存到文本文件
SaveHistogramValues(frameFolder, frameIndex, blueHistogram, redHistogram, greenHistogram);
// 保存 ZedGraph 控件的屏幕截图
SaveGraphScreenshots(frameFolder, redHistogram, greenHistogram, blueHistogram);
// 更新 PictureBox 中的帧
pictureBox1.Invoke(new Action(() =>
{
pictureBox1.Image = frame;
pictureBox1.Refresh();
}));
// 更新进度条
progressBar1.Invoke(new Action(() =>
{
progressBar1.Value = frameIndex + 1;
}));
// 延迟以减慢处理速度(根据需要进行调整)
await Task.Delay(10);
}
});
// 处理完所有帧后刷新图形
zedGraphControl1.AxisChange();
zedGraphControl1.Refresh();
// 显示处理完成的消息
MessageBox.Show("视频处理完成。");
// 提取完成后重新启用按钮
btnOpenVideo.Enabled = true;
}
}
}
}
// 最后调用 SaveGraphScreenshots 方法。
private void SaveGraphScreenshots(string frameFolderPath, int[] redHistogram, int[] greenHistogram, int[] blueHistogram)
{
if (redHistogram.Any() || greenHistogram.Any() || blueHistogram.Any())
{
if (blueHistogram.Any())
{
string graphFilePath = Path.Combine(frameFolderPath, "HistogramGraph.png");
SaveGraphScreenshot(zedGraphControl1, graphFilePath);
}
if (redHistogram.Any())
{
string redGraphFilePath = Path.Combine(frameFolderPath, "RedHistogramGraph.png");
SaveGraphScreenshot(zedGraphControl1, redGraphFilePath);
}
if (greenHistogram.Any())
{
string greenGraphFilePath = Path.Combine(frameFolderPath, "GreenHistogramGraph.png");
SaveGraphScreenshot(zedGraphControl1, greenGraphFilePath);
}
}
}
英文:
a bit long but it's all connected.
I'm assigning in this method to the channelValue according to the channelColor:
private int[] CalculateChannelHistogram(Bitmap image, Color channelColor)
{
int[] histogram = new int[256];
BitmapData imageData = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
unsafe
{
byte* ptr = (byte*)imageData.Scan0;
for (int y = 0; y < imageData.Height; y++)
{
for (int x = 0; x < imageData.Width; x++)
{
byte channelValue = 0;
if (channelColor == Color.Red)
channelValue = ptr[y * imageData.Stride + x * 4 + 2];
else if (channelColor == Color.Green)
channelValue = ptr[y * imageData.Stride + x * 4 + 1];
else if (channelColor == Color.Blue)
channelValue = ptr[y * imageData.Stride + x * 4];
histogram[channelValue]++;
}
}
}
image.UnlockBits(imageData);
return histogram;
}
then using it in this button click event:
private async void btnOpenVideo_Click(object sender, EventArgs e)
{
// Initialize the CancellationTokenSource
cancellationTokenSource = new CancellationTokenSource();
// Initialize the histograms list
histograms = new List<int[]>();
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "Video Files (*.mp4;*.avi;*.mkv)|*.mp4;*.avi;*.mkv|All files (*.*)|*.*";
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string videoPath = openFileDialog.FileName;
// Open the video file using VideoFileReader
using (VideoFileReader videoReader = new VideoFileReader())
{
videoReader.Open(videoPath);
// Get the total number of frames in the video
int totalFrames = (int)videoReader.FrameCount;
// Clear any existing curves on the graph
zedGraphControl1.GraphPane.CurveList.Clear();
// Set the maximum value of the progress bar
progressBar1.Value = 0;
progressBar1.Maximum = totalFrames;
// Disable the button to prevent multiple extractions
btnOpenVideo.Enabled = false;
histograms.Clear();
// Process each frame in the video
await Task.Run(async () =>
{
for (int frameIndex = 0; frameIndex < totalFrames; frameIndex++)
{
// Check if cancellation is requested
if (cancellationTokenSource.IsCancellationRequested)
break;
// Read the video frame
Bitmap frame = videoReader.ReadVideoFrame(frameIndex);
// Calculate and display histograms
int[] grayscaleHistogram = CalculateGrayscaleHistogram(frame);
int[] redHistogram = CalculateChannelHistogram(frame, Color.Red);
int[] greenHistogram = CalculateChannelHistogram(frame, Color.Green);
int[] blueHistogram = CalculateChannelHistogram(frame, Color.Blue);
histograms.Add(grayscaleHistogram);
// Plot histograms
PlotHistogram(grayscaleHistogram, "Grayscale Histogram", "Pixel Value", "Frequency", zedGraphControl1.GraphPane, Color.Blue);
PlotHistogram(redHistogram, "Red Channel Histogram", "Pixel Value", "Frequency", zedGraphControl1.GraphPane, Color.Red);
PlotHistogram(greenHistogram, "Green Channel Histogram", "Pixel Value", "Frequency", zedGraphControl1.GraphPane, Color.Green);
PlotHistogram(blueHistogram, "Blue Channel Histogram", "Pixel Value", "Frequency", zedGraphControl1.GraphPane, Color.Blue);
// Draw histogram information on the frame
DrawHistogramInformation(frame, grayscaleHistogram, "Grayscale Histogram");
// Save frame with histogram
string frameFolder = Path.Combine(outputFolder, $"Frame_{frameIndex}");
if(!Directory.Exists(frameFolder))
{
Directory.CreateDirectory(frameFolder);
}
string frameImagePath = Path.Combine(frameFolder, $"Frame_{frameIndex}.png");
frame.Save(frameImagePath, ImageFormat.Png);
// Save histogram values to text file
SaveHistogramValues(frameFolder, frameIndex, blueHistogram, redHistogram, greenHistogram);
// Save screenshot of ZedGraph controls
SaveGraphScreenshots(frameFolder, redHistogram, greenHistogram, blueHistogram);
// Update the PictureBox with the frame
pictureBox1.Invoke(new Action(() =>
{
pictureBox1.Image = frame;
pictureBox1.Refresh();
}));
// Update the progress bar
progressBar1.Invoke(new Action(() =>
{
progressBar1.Value = frameIndex + 1;
}));
// Delay to slow down the processing (adjust as needed)
await Task.Delay(10);
}
});
// Refresh the graph after processing all frames
zedGraphControl1.AxisChange();
zedGraphControl1.Refresh();
// Show a message indicating the processing is complete
MessageBox.Show("Video processing completed.");
// Re-enable the button after extraction is complete
btnOpenVideo.Enabled = true;
}
}
}
}
then last calling the SaveGraphScreenshots method:
in this SaveGraphScreenshots method I want to save a screenshot image to the hard drive of the channel color chart but only if the channel color have any data. for example some frames can have data on channel red and green or only blue or only red but it keep saving all the channels it give it the names GreenHistogramGraph.png , HistogramGraph.png, RedHistogramGraph.png
where HistogramGraph.png is the blue channel.
and when I'm editing in paint the images they are all the same blue channel.
I want to save only the channels that have data inside. blue green red. but it's saving only the same blue color channel just give different files names.
private void SaveGraphScreenshots(string frameFolderPath, int[] redHistogram, int[] greenHistogram, int[] blueHistogram)
{
if (redHistogram.Any() || greenHistogram.Any() || blueHistogram.Any())
{
if (blueHistogram.Any())
{
string graphFilePath = Path.Combine(frameFolderPath, "HistogramGraph.png");
SaveGraphScreenshot(zedGraphControl1, graphFilePath);
}
if (redHistogram.Any())
{
string redGraphFilePath = Path.Combine(frameFolderPath, "RedHistogramGraph.png");
SaveGraphScreenshot(zedGraphControl1, redGraphFilePath);
}
if (greenHistogram.Any())
{
string greenGraphFilePath = Path.Combine(frameFolderPath, "GreenHistogramGraph.png");
SaveGraphScreenshot(zedGraphControl1, greenGraphFilePath);
}
}
}
答案1
得分: 2
.Any()
检查集合中是否有任何项,而这将始终为真,因为直方图无条件地包含256个整数。
您可能想要做的是检查集合中是否有任何值大于零,除了零索引。即:
if (redHistogram.Skip(1).Any(v => v > 0))
英文:
> if (redHistogram.Any())
.Any()
checks if there is any item in the collection, and this will always be true, since the histogram will unconditionally contain 256 integers.
What you probably want to do is check if there is any value in the collection, except the zero index, that is larger than zero. I.e.
if (redHistogram.Skip(1).Any(v => v > 0))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论