Adaptive Parallel Threshold

public static double VariableThresholdingLocalPropertiesParallel(Bitmap image, double a, double b)
{
    int w = image.Width;
    int h = image.Height;

    BitmapData image_data = image.LockBits(
        new Rectangle(0, 0, w, h),
        ImageLockMode.ReadOnly,
        PixelFormat.Format24bppRgb);

    int bytes = image_data.Stride * image_data.Height;
    byte[] buffer = new byte[bytes];

    Marshal.Copy(image_data.Scan0, buffer, 0, bytes);
    image.UnlockBits(image_data);

    // Get global mean - this works only for grayscale images
    double mg = 0;
    for (int i = 0; i < bytes; i += 3)
    {
        mg += buffer[i];
    }
    mg /= (w * h);

    // 병렬 처리 μ€€λΉ„: μž„κ³„κ°’μ˜ λˆ„μ  ν•©κ³Ό ν”½μ…€ 수
    double cumulativeThreshold = 0;
    int count = 0;
    object lockObject = new object(); // 동기화 객체

    Parallel.For(1, w - 1, x =>
    {
        double localCumulativeThreshold = 0; // 각 μŠ€λ ˆλ“œμ—μ„œ μž„κ³„κ°’ λˆ„μ  ν•©μ‚°
        int localCount = 0; // 각 μŠ€λ ˆλ“œμ—μ„œ μ²˜λ¦¬ν•œ ν”½μ…€ 수

        for (int y = 1; y < h - 1; y++)
        {
            int position = x * 3 + y * image_data.Stride;
            double mean = 0;
            double std = 0;

            // 3x3 μ£Όλ³€ ν”½μ…€μ˜ 평균과 ν‘œμ€€ 편차 계산
            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    int nposition = position + i * 3 + j * image_data.Stride;
                    byte pixelValue = buffer[nposition];
                    mean += pixelValue;
                    std += pixelValue * pixelValue;
                }
            }

            mean /= 9.0;
            std = Math.Sqrt(std / 9.0 - mean * mean);

            // μž„κ³„κ°’ 계산
            double threshold = a * std + b * mg;
            localCumulativeThreshold += threshold;
            localCount++;
        }

        // λˆ„μ λœ κ²°κ³Όλ₯Ό 메인 λ³€μˆ˜μ— 병합
        lock (lockObject)
        {
            cumulativeThreshold += localCumulativeThreshold;
            count += localCount;
        }
    });

    // λͺ¨λ“  ν”½μ…€μ˜ 평균 μž„κ³„κ°’μ„ λ°˜ν™˜
    return cumulativeThreshold / count;
}