将错误级别分析的 C++ 实现转换为 C#

Posted

技术标签:

【中文标题】将错误级别分析的 C++ 实现转换为 C#【英文标题】:Converting a C++ implementation of Error Level Analysis to C# 【发布时间】:2021-04-01 05:33:54 【问题描述】:

我正在尝试在 C# 中实现 Error Level Analysis。我在使用 OpenCV 的 C++ 和使用 PIL 的 Python 中找到了示例,但在 C# 中找不到任何示例,因此我正在尝试使用 OpenCvSharp 库转换 C++ 代码。

这是我使用的示例:

// Control
int scale = 15,
quality = 75;

// Image containers
cv::Mat input_image,
compressed_image;

void processImage(int, void*)

    // Setting up parameters and JPEG compression
    std::vector<int> parameters;
    parameters.push_back(CV_IMWRITE_JPEG_QUALITY);
    parameters.push_back(quality);
    cv::imwrite("temp.jpg", input_image, parameters);

    // Reading temp image from the disk
    compressed_image = cv::imread("temp.jpg");
 
    if (compressed_image.empty())
    
        std::cout << "> Error loading temp image" << std::endl;
        exit(EXIT_FAILURE);
    

    cv::Mat output_image = cv::Mat::zeros(input_image.size(), CV_8UC3);

    // Compare values through matrices
    for (int row = 0; row < input_image.rows; ++row)
    
        const uchar* ptr_input = input_image.ptr<uchar>(row);
        const uchar* ptr_compressed = compressed_image.ptr<uchar>(row);
        uchar* ptr_out = output_image.ptr<uchar>(row);
   
        for (int column = 0; column < input_image.cols; column++)
        
            // Calc abs diff for each color channel multiplying by a scale factor
            ptr_out[0] = abs(ptr_input[0] - ptr_compressed[0]) * scale;
            ptr_out[1] = abs(ptr_input[1] - ptr_compressed[1]) * scale;
            ptr_out[2] = abs(ptr_input[2] - ptr_compressed[2]) * scale;

            ptr_input += 3;
            ptr_compressed += 3;
            ptr_out += 3;
        
    

    // Shows processed image
    cv::imshow("Error Level Analysis", output_image);

这是我目前的尝试:

[STAThread]
static void Main(string[] args)

    // Control
    int scale = 15;
    int quality = 75;

    string test_img_path = "";
    // Image container
    OpenFileDialog fdlg = new OpenFileDialog();
    fdlg.Title = "C# Corner Open File Dialog";
    fdlg.InitialDirectory = @"c:\Documents\Pictures";
    fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*";
    fdlg.FilterIndex = 2;
    fdlg.RestoreDirectory = true;
    if (fdlg.ShowDialog() == DialogResult.OK)
    
        test_img_path = fdlg.FileName;
    

    Mat input_image = Cv2.ImRead(test_img_path);
    Mat compressed_image;
    // Setting up parameters and JPEG compression

    int[] Params = new int[2];
    Params.Append(95);
    Params.Append(50);
    Cv2.ImWrite("temp.jpg", input_image, Params);

    // Reading temp image from the disk
    compressed_image = Cv2.ImRead("temp.jpg");

    if (compressed_image.Empty())
    
        Trace.WriteLine("File empty");
    

    Mat output_image = Mat.Zeros(input_image.Size(), MatType.CV_8UC3);

    // Compare values through matrices
    for (int row = 0; row < input_image.Rows; ++row)
    
        unsafe
        
            char* ptr_input = (char*)input_image.Ptr(row);
            char* ptr_compressed = (char*)compressed_image.Ptr(row);
            char* ptr_out = (char*)output_image.Ptr(row);

            for (int column = 0; column < input_image.Cols; column++)
            
                // Calc abs diff for each color channel multiplying by a scale factor
                ptr_out[0] = (char)((ptr_input[0] - ptr_compressed[0]) * scale);
                ptr_out[1] = (char)(Math.Abs(ptr_input[1] - ptr_compressed[1]) * scale);
                ptr_out[2] = (char)(Math.Abs(ptr_input[2] - ptr_compressed[2]) * scale);

                ptr_input += 3;
                ptr_compressed += 3;
                ptr_out += 3;
            
        
    

    // Shows processed image
    Cv2.ImShow("Error Level Analysis", output_image);

以上将无法编译,并导致错误:

试图读取或写入受保护的内存。这通常表明其他内存已损坏。

任何关于转换的帮助,或使用 C# 进行 ELA 的方法,我们将不胜感激。

【问题讨论】:

你已经说明了一切,但问题是。怎么了?这管用吗?您没有得到预期的结果吗? 我已经对其进行了编辑以说明问题 - 它根本不起作用,我不确定是什么问题。 OpenCvSharp 文档非常薄,尝试直接转换语法似乎不起作用 - 我希望我能更准确,但老实说,我什至不确定是什么不起作用。跨度> 你提到:"。上面的代码不会编译..."。能否请您把编译错误,以便我们可以帮助您,而无需在其他地方重现代码? @SebastianInones 我已经更新了代码并提供了我得到的错误,任何帮助将不胜感激! 您使用的 opencv 库的名称是什么? OpenCvSharp? 【参考方案1】:

// 控制 整数比例 = 15; int 质量 = 75;

        // Image containers
        Mat input_image = new Mat();
        Mat compressed_image;
        // Setting up parameters and JPEG compression


        int[] Params = new int[2];
        Params.Append(95);
        Params.Append(50);
        Cv2.ImWrite("temp.jpg", input_image, Params);

        // Reading temp image from the disk
        compressed_image = Cv2.ImRead("temp.jpg");

        if (compressed_image.Empty())
        
            Trace.WriteLine("File empty");
        

        Mat output_image = Mat.Zeros(input_image.Size(), MatType.CV_8UC3);

        // Compare values through matrices
        for (int row = 0; row < input_image.Rows; ++row)
        
            unsafe
            
                char* ptr_input = (char*)input_image.Ptr(row);
                char* ptr_compressed = (char*)compressed_image.Ptr(row);
                char* ptr_out = (char*)output_image.Ptr(row);

                for (int column = 0; column < input_image.Cols; column++)
                
                    // Calc abs diff for each color channel multiplying by a scale factor
                    ptr_out[0] = (char)((ptr_input[0] - ptr_compressed[0]) * scale);
                    ptr_out[1] = (char)(Math.Abs(ptr_input[1] - ptr_compressed[1]) * scale);
                    ptr_out[2] = (char)(Math.Abs(ptr_input[2] - ptr_compressed[2]) * scale);

                    ptr_input += 3;
                    ptr_compressed += 3;
                    ptr_out += 3;
                
            

        

        // Shows processed image
        Cv2.ImShow("Error Level Analysis", output_image);

【讨论】:

您好,感谢您的帮助,我在 ptr_out[0] 上收到以下错误......: System.AccessViolationException: '尝试读取或写入受保护的内存。这通常表明其他内存已损坏。'【参考方案2】:

可以通过以下代码访问像素值。您不能通过指针访问受保护的内存。

using Mat mat = new Mat(FilePath.Image.Lenna, ImreadModes.Color);
            for (int y = 0; y < mat.Height; y++)
            
                for (int x = 0; x < mat.Width; x++)
                
                    Vec3b color = mat.Get<Vec3b>(y, x);
                    Vec3b newColor = new Vec3b(color.Item2, color.Item1, color.Item0);
                    mat.Set<Vec3b>(y, x, newColor);
                
            

在c#中有很多如何使用opencv的例子。检查here。

【讨论】:

【参考方案3】:

您可以改用EmguCV,您可以从here 安装它。然后你可以像这样将代码转换为 C#。

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Emgu.CV;
using Emgu.CV.CvEnum;

class Program

    // Control
    readonly int scale = 15, quality = 75;

    // Image containers
    Mat input_image, compressed_image;

    void ProcessImage()
    
        // Setting up parameters and JPEG compression
        KeyValuePair<ImwriteFlags, int> parameters = new KeyValuePair<ImwriteFlags, int>(ImwriteFlags.JpegQuality, quality);
        CvInvoke.Imwrite("temp.jpg", input_image, parameters);

        // Reading temp image from the disk
        compressed_image = CvInvoke.Imread("temp.jpg");

        if (compressed_image.IsEmpty)
        
            Console.WriteLine("> Error loading temp image");
            Environment.Exit(1);
        

        Mat output_image = Mat.Zeros(input_image.Rows, input_image.Cols, DepthType.Cv8U, 3);

        byte[] input, compressed, output;
        input = new byte[input_image.Rows* input_image.Cols* 3];
        compressed = new byte[input_image.Rows * input_image.Cols * 3];
        output = new byte[input_image.Rows * input_image.Cols * 3];
        input_image.CopyTo(input);
        compressed_image.CopyTo(compressed);

        // Compare values through matrices
        for (int row = 0; row < input_image.Rows; ++row)
            for (int column = 0; column < input_image.Cols; column++)
                for (int channel = 0; channel < 3; channel++)
                    // Calc abs diff for each color channel multiplying by a scale factor
                    output[(row * input_image.Cols + column) * 3 + channel] = (byte)(Math.Abs(input[(row * input_image.Cols + column) * 3 + channel] - compressed[(row * input_image.Cols + column) * 3 + channel]) * scale);

        byte[] t = new byte[1];  
        for (int i = 0; i < output.Length; i++)
        
            t[0] = output[i];
            Marshal.Copy(t, 0, output_image.DataPointer + i, 1);
        

        // Shows processed image
        CvInvoke.Imshow("Error Level Analysis", output_image); 
    

【讨论】:

感谢您的帮助。不幸的是,我收到了错误:System.NullReferenceException: 'Object reference not set to an instance of an object.' in regards to the 'Mat Input Image' 虽然如果我将它设置为:Mat Input Image = CvInvoke.Imread(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "ela_frog.jpg"), Emgu.CV.CvEnum.ImreadModes.AnyColor); 然后会显示图像,但它有很多灰色模糊线而不是 ELA。 @Retro 立即尝试。我将数组转换为Mat时出错了,但现在它可以工作了,我将它与C++结果进行了比较。 感谢您的帮助,这是完美的。对于未来的读者,我创建了 input_image Mat:Mat input_image = CvInvoke.Imread(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ela_test_1.jpg"), ImreadModes.AnyColor);

以上是关于将错误级别分析的 C++ 实现转换为 C#的主要内容,如果未能解决你的问题,请参考以下文章

如何将带有 Union 的 C++ 结构转换为 C#?

将包含结构的 c++ 函数传递给 C#,并使用 Marshal.PtrToStructure 将其转换为 c# 函数

C# COM 与 C++ COM 返回值

使用 C# 中的 NAudio 将 M4A 音频文件转换为 MP3 的问题/错误

C++ 将字符串传递到 C# dll

从未见过 C++ for 循环