Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.50/30: Рейтинг темы: голосов - 30, средняя оценка - 4.50
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676

Добавить к коду подсчет яркостей

22.09.2020, 09:49. Показов 7805. Ответов 124
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
C#
1
2
3
4
5
6
7
8
9
                foreach (var p in source)
                {
                    //get pixel from dithering matrix
                    var dithPixel = dith[p.X % dith.Width, p.Y % dith.Height].GetBrightness();
                    //get pixel from source image
                    var pixel = source[p].GetBrightness();
                    //compare
                    res[p] = pixel >= dithPixel ? Color.White : Color.Black;
                }
Вот такой код есть из темы.
Хочу расширить код подсчитывая количество значений яркости dithPixel например в виде структуры [Value, Count], но не могу вспомнить как это сделать через хеши (именованные массивы).
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.09.2020, 09:49
Ответы с готовыми решениями:

Добавить к коду подсчет вызовов функции
помогите добавить подсчет вызовов функции,вообще не знаю,как symbol = 's' height = 3 width = 3 counter = 3 def dec1(f): ...

Подсчёт суммы значений в ячейках по столбцу по коду товара
Для упрощения. Вот есть две таблицы. Первая с двумя столбцами и кучей строк. 1 столбец в ней - это код товара, 2 столбец - цена. Товар...

Добавить комментарии к коду
Здравствуйте. Кто сможет закомментировать код? <script language="JavaScript"> var elements = document.URL.substr(8).split(/\/|\\/); ...

124
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
30.09.2020, 13:45
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от belalugoci Посмотреть сообщение
Не понял.
Давно не делал формы.
Вот полный Code Behind.
Метод режет заданное количество точек.
В примере исходное изображение и его срезы по 25%, 50% и 75% количества точек.
Форма адаптивная - размеры рисунком подстраиваются под изменения размеров формы.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
using System;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Forms2009
{
    public partial class Form1 : Form
    {
        Bitmap ImageSource,
            ImageResult25, ImageResult50, ImageResult75;
 
        PictureBox pictureBox0 = new PictureBox(),
            pictureBox1 = new PictureBox(),
            pictureBox2 = new PictureBox(),
            pictureBox3 = new PictureBox();
        public Form1()
        {
            InitializeComponent();
            pictureBox0.SizeMode = pictureBox1.SizeMode = pictureBox2.SizeMode = pictureBox3.SizeMode = PictureBoxSizeMode.Zoom;
            pictureBox0.Parent = pictureBox1.Parent = pictureBox2.Parent = pictureBox3.Parent = this;
            SizeChanged += FormSizeChanged;
            WindowState = FormWindowState.Maximized;
 
            pictureBox0.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\EldHa\OneDrive\Изображения\ashim-d-silva-WeYamle9fDM-unsplash.jpg");
            //pictureBox1.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\EldHa\OneDrive\Изображения\Ярлыки\HardForum — копия.gif");
            pictureBox1.Image = ImageResult25 = BlackWhiteImage(ImageSource, 0.25);
            pictureBox2.Image = ImageResult50 = BlackWhiteImage(ImageSource, 0.5);
            pictureBox3.Image = ImageResult75 = BlackWhiteImage(ImageSource, 0.75);
        }
 
        private void FormSizeChanged(object sender, EventArgs e)
        {
            int width = Width / 2 - 5;
            int height = Height / 2 - 5;
 
            pictureBox0.Width = pictureBox1.Width = pictureBox2.Width = pictureBox3.Width = width;
            pictureBox0.Height = pictureBox1.Height = pictureBox2.Height = pictureBox3.Height = height;
 
            pictureBox0.Left = 0;
            pictureBox0.Top = 0;
 
            pictureBox1.Left = width + 10;
            pictureBox1.Top = 0;
 
            pictureBox2.Left = 0;
            pictureBox2.Top = height + 10;
 
            pictureBox3.Left = width + 10;
            pictureBox3.Top = height + 10;
 
        }
 
        /// <summary>Контейнер для связанных данных по яркости изображения.</summary>
        public class BrightnesData
        {
            /// <summary>Массив Яркостей.</summary>
            public int[,] Brightnes { get; }
            /// <summary>Массив кортежей яркостей и количества точек с такой яркостью.</summary>
            public (int brightne, int count)[] BrightnesCounts { get; }
 
            public BrightnesData(int[,] brightnes, (int brightne, int count)[] brightnesCounts)
            {
                Brightnes = brightnes;
                BrightnesCounts = brightnesCounts;
            }
        }
 
        /// <summary>Преобразует пиксельное цветное изображение в массив in[,] яркостей.</summary>
        /// <param name="bmp">Цветное изображение в формате bmp.</param>
        /// <param name="tasksCount">Количество потоков для расчёта. По умолчанию - 10 потоков.</param>
        /// <returns>Контейнер <see cref="BrightnesData"/> с двумя свойствами:<br/>
        /// <see cref="BrightnesData.Brightnes"/> - Матрица int[,] яркостей пикселей.<br/>
        /// Значения яркостей в истинных целых единицах.<br/>
        /// Отличаются от значений <see cref="Color.GetBrightness"/> в 510 раз.<br/>
        /// и <see cref="BrightnesData.BrightnesCounts"/> - Отсортированный массив<br/>
        /// имеющихся различных яркостей и количества точек с такой яркостю.</returns>
        public static BrightnesData GetBrightnes(Bitmap bmp, int tasksCount = 10)
        {
 
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            int stride = bmpData.Stride;
            byte[] bmpBytes = new byte[stride * bmp.Height];
            System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, bmpBytes, 0, bmpBytes.Length);
            bmp.UnlockBits(bmpData);
 
            int[,] brightnes = new int[bmp.Height, bmp.Width];
 
            int[] brightnesCounts = new int[511];
 
            int height = bmp.Height;
            int width = bmp.Width;
            Task[] tasks = new Task[tasksCount];
            rowCalkData data = new rowCalkData()
            {
                length = height / tasksCount,
                bmpBytes = bmpBytes,
                brightnes = brightnes,
                brightnesCounts = brightnesCounts
            };
 
            int mod = height % tasksCount;
            int counRow = 0;
 
            for (int num = 0; num < tasksCount; num++)
            {
                rowCalkData _data = data;
                _data.rowBegin = counRow;
                if (mod-- > 0)
                    _data.length++;
 
                counRow += _data.length;
 
                tasks[num] = Task.Factory.StartNew(RowCalk, _data);
            }
 
            Task.WaitAll(tasks);
 
            (int brightne, int count)[] brightnesCountsSort = brightnesCounts
                .Select((cnt, br) => (brightne: br, count: cnt))
                .Where(pr => pr.count > 0)
                .OrderBy(pr => pr.count)
                .ToArray();
 
            return new BrightnesData(brightnes, brightnesCountsSort);
 
        }
        struct rowCalkData
        {
            public int rowBegin;
            public int length;
            public byte[] bmpBytes;
            public int[,] brightnes;
            public int[] brightnesCounts;
        }
        // Mетод для расчёта яркостей диапазона строк
        static void RowCalk(object obj)
        {
            rowCalkData data = (rowCalkData)obj;
 
            int width = data.brightnes.GetLength(1);
            int brightne;
            int k = data.rowBegin * width * 4;
            int rowEnd = data.rowBegin + data.length;
 
            for (int row = data.rowBegin; row < rowEnd; row++)
            {
 
                for (int col = 0; col < width; col++)
                {
                    int r = data.bmpBytes[k++];
                    int g = data.bmpBytes[k++];
                    int b = data.bmpBytes[k++];
                    int min = r, max = r;
                    if (g > max) max = g;
                    if (b > max) max = b;
 
                    if (g < min) min = g;
                    if (b < min) min = b;
 
                    brightne = min + max;
                    data.brightnesCounts[data.brightnes[row, col] = brightne]++;
                    k++;
                }
            }
 
        }
 
        /// <summary>Конвертация в чёрно белое изображение.</summary>
        /// <param name="bmp">Исходное изображение.</param>
        /// <param name="average">Доля срезаемых точек.</param>
        /// <returns></returns>
        internal static Bitmap BlackWhiteImage(Bitmap bmp, double average)
        {
            var source = GetBrightnes(bmp);
            byte[] argb = new byte[source.Brightnes.Length * 4];
 
            // Уровень срезаемой яркости
            int avbr = 0;
            double countPixels = 0;
            foreach (var item in source.BrightnesCounts.OrderBy(x => x.brightne))
            {
                avbr = item.brightne;
                countPixels += item.count;
                if (countPixels / source.Brightnes.Length > average)
                    break;
            }
 
            int k = 0;
            for (int row = 0; row < source.Brightnes.GetLength(0); row++)
                for (int col = 0; col < source.Brightnes.GetLength(1); col++)
                {
                    int brightne = source.Brightnes[row, col];
                    if (brightne > avbr)
                    {
                        argb[k++] = 255;
                        argb[k++] = 255;
                        argb[k++] = 255;
                    }
                    else
                    {
                        argb[k++] = 0;
                        argb[k++] = 0;
                        argb[k++] = 0;
                    }
                    argb[k++] = 255;
                }
            //}
 
            var zero = argb.Count(x => x == 0);
 
            var result = new Bitmap(bmp.Width, bmp.Height);
            BitmapData bmpData = result.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            int stride = bmpData.Stride;
            //byte[] bmpBytes = new byte[stride * bmp.Height];
            System.Runtime.InteropServices.Marshal.Copy(argb, 0, bmpData.Scan0, argb.Length);
            result.UnlockBits(bmpData);
 
            return result;
        }
 
    }
}
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
30.09.2020, 13:48
Цитата Сообщение от belalugoci Посмотреть сообщение
Перед using переменные ввёл и ниже их использовал, стало работать и рисовать, но всякую ерунду.
Там было много мелких ошибок.
Но вроде все устранил.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
30.09.2020, 13:58  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Там было много мелких ошибок.
Но вроде все устранил.
Спасибо, завтра гляну, но пока для меня там дичь какая-то ))))
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
30.09.2020, 14:08
Цитата Сообщение от belalugoci Посмотреть сообщение
но пока для меня там дичь какая-то ))))
Математика!
Чёрт её побери!
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,576
30.09.2020, 15:51
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Там было много мелких ошибок.
Но вроде все устранил.
По прежнему считает неправильно из-за отсутствия синхронизации между потоками при записи в общий массив.

Вот выкладываю исправленный вариант и еще 3 других варианта в тестовом проекте с бенчмарком.
Варианты GetBrightnessSafe и GetBrightnessV4 (ваш последний с моим исправлением) выдают примерно одинаковую скорость (у меня ~40мс), но всё равно уступают почти в 2 раза варианту с unsafe доступом к массиву (~20мс).
Вложения
Тип файла: zip BrightnessCounts.zip (10.7 Кб, 3 просмотров)
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
30.09.2020, 17:31
Цитата Сообщение от Someone007 Посмотреть сообщение
По прежнему считает неправильно из-за отсутствия синхронизации между потоками при записи в общий массив.
А зачем там синхронизация....?


Только если я там где-то ошибся, но там надо тогда искать логику в ошибке.
У каждой задачи свой диапазон массива и они никак не перекрешиваются.
От синхронизации (в данном случае) только доп задержки будут.

Я обработал пару рисунков - судя по эффектам работает правильно.

Добавлено через 2 минуты
Цитата Сообщение от Someone007 Посмотреть сообщение
, но всё равно уступают почти в 2 раза варианту с unsafe доступом к массиву (~20мс).
С unsafe я не стал возиться, поскольку для него лучше сделать отдельную сборку с готовым типом.

И у меня не получается нормально протестировать - старый комп.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,576
30.09.2020, 17:32
Цитата Сообщение от Элд Хасп Посмотреть сообщение
А зачем там синхронизация....?
Потому что количество яркостей каждый раз у вас было разное. Уберите синхронизацию и запустите мой проект и увидите...

Цитата Сообщение от Элд Хасп Посмотреть сообщение
У каждой задачи свой диапазон массива и они никак не перекрешиваются.
Перекрещиваются при подсчете количества яркостей.
C#
1
data.brightnes[row, col] = brightne // тут все хорошо, т.к. у каждого потока свой диапазон
C#
1
data.brightnesCounts[brightne]++; // а вот тут проблема, т.к. массив общий на все потоки
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
30.09.2020, 17:36
Цитата Сообщение от Someone007 Посмотреть сообщение
из-за отсутствия синхронизации
Я, к стати, по этой причине и заменил локальный метод на статический.
Чтобы случайно не захватить локальные переменные.

Добавлено через 2 минуты
Цитата Сообщение от Someone007 Посмотреть сообщение
а вот тут проблема, т.к. массив общий на все потоки
Опаньки!
Вы правы.
Я эту часть не доделал когда с локального метода убирал.
Но там не синхронизация нужна.
Сейчас занят часа через три исправлю и скину другой варинат.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
30.09.2020, 20:51
belalugoci, исправил указанную Someone007 ошибку в логике и добавил комментариев:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
using System;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Forms2009
{
    public partial class Form1 : Form
    {
        Bitmap ImageSource,
            ImageResult25, ImageResult50, ImageResult75;
 
        PictureBox pictureBox0 = new PictureBox(),
            pictureBox1 = new PictureBox(),
            pictureBox2 = new PictureBox(),
            pictureBox3 = new PictureBox();
        public Form1()
        {
            InitializeComponent();
 
            // Установка параметров рисунков
            pictureBox0.SizeMode = pictureBox1.SizeMode = pictureBox2.SizeMode = pictureBox3.SizeMode = PictureBoxSizeMode.Zoom;
            pictureBox0.Parent = pictureBox1.Parent = pictureBox2.Parent = pictureBox3.Parent = this;
 
            // Подключение прослушки к изменению размера Формы
            SizeChanged += FormSizeChanged;
 
            // Разворачивание Формы
            WindowState = FormWindowState.Maximized;
 
            // Чтение рисунка, его сохранение в поле и вывод на форму.
            pictureBox0.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\EldHa\OneDrive\Изображения\ashim-d-silva-WeYamle9fDM-unsplash.jpg");
            //pictureBox1.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\EldHa\OneDrive\Изображения\Ярлыки\HardForum — копия.gif");
 
            // Получение матрицы яркости в истинных единицах и массива статистики яркостей
            BrightnesData brightnes = GetBrightnes(ImageSource);
 
            // Получение чёрно-белых рисунков из матрицы яркостей с разной долей отсечки точек
            pictureBox1.Image = ImageResult25 = BlackWhiteImage(brightnes, 0.25);
            pictureBox2.Image = ImageResult50 = BlackWhiteImage(brightnes, 0.5);
            pictureBox3.Image = ImageResult75 = BlackWhiteImage(brightnes, 0.75);
        }
 
        /// <summary>Метод адаптации размеров рисунки под изменение размеров Формы.</summary>
        private void FormSizeChanged(object sender, EventArgs e)
        {
            int width = Width / 2 - 5;
            int height = Height / 2 - 5;
 
            pictureBox0.Width = pictureBox1.Width = pictureBox2.Width = pictureBox3.Width = width;
            pictureBox0.Height = pictureBox1.Height = pictureBox2.Height = pictureBox3.Height = height;
 
            pictureBox0.Left = 0;
            pictureBox0.Top = 0;
 
            pictureBox1.Left = width + 10;
            pictureBox1.Top = 0;
 
            pictureBox2.Left = 0;
            pictureBox2.Top = height + 10;
 
            pictureBox3.Left = width + 10;
            pictureBox3.Top = height + 10;
 
        }
 
        /// <summary>Контейнер для возврата из метода связанных данных по яркости изображения.</summary>
        public class BrightnesData
        {
            /// <summary>Массив Яркостей.</summary>
            public int[,] Brightnes { get; }
            /// <summary>Массив кортежей яркостей и количества точек с такой яркостью.</summary>
            public (int brightne, int count)[] BrightnesCounts { get; }
            /// <summary>Создание экземпляра типа.</summary>
            /// <param name="brightnes">Массив Яркостей.</param>
            /// <param name="brightnesCounts">Массив кортежей яркостей и количества точек с такой яркостью.</param>
            public BrightnesData(int[,] brightnes, (int brightne, int count)[] brightnesCounts)
            {
                Brightnes = brightnes;
                BrightnesCounts = brightnesCounts;
            }
        }
 
        /// <summary>Преобразует пиксельное цветное изображение в массив in[,] яркостей.</summary>
        /// <param name="bmp">Цветное изображение в формате bmp.</param>
        /// <param name="tasksCount">Количество потоков для расчёта. По умолчанию - 10 потоков.</param>
        /// <returns>Контейнер <see cref="BrightnesData"/> с двумя свойствами:<br/>
        /// <see cref="BrightnesData.Brightnes"/> - Матрица int[,] яркостей пикселей.<br/>
        /// Значения яркостей в истинных целых единицах.<br/>
        /// Отличаются от значений <see cref="Color.GetBrightness"/> в 510 раз.<br/>
        /// и <see cref="BrightnesData.BrightnesCounts"/> - Отсортированный массив<br/>
        /// имеющихся различных яркостей и количества точек с такой яркостю.</returns>
        public static BrightnesData GetBrightnes(Bitmap bmp, int tasksCount = 10)
        {
            // Получение байтового массива рисунка. Байты получаются в последовательности Format32bppArgb
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            int stride = bmpData.Stride;
            byte[] bmpBytes = new byte[stride * bmp.Height];
            System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, bmpBytes, 0, bmpBytes.Length);
            bmp.UnlockBits(bmpData);
 
            // Создание массива яркостей и массива для подсчёта количества точек с каждой яркостью
            int[,] brightnes = new int[bmp.Height, bmp.Width];
            int[] brightnesCounts = new int[511];
 
            // Инициализация локальных переменных и структуры для передачи данных в задачи
            int height = bmp.Height;
            int width = bmp.Width;
            Task<int[]>[] tasks = new Task<int[]>[tasksCount];
            RowCalkData data = new RowCalkData()
            {
                length = height / tasksCount,
                bmpBytes = bmpBytes,
                brightnes = brightnes
            };
 
            // Если количество строк не кратно количеству потоков, то определятся сколь "лишних строк"
            int mod = height % tasksCount;
 
            // Количество переданных в обработку строк
            int counRow = 0;
 
            // Цикл для создания и запуска задач
            for (int num = 0; num < tasksCount; num++)
            {
                // Копирование контейнера с данными для передачи в задачу.
                RowCalkData _data = data;
 
                // Задание начальной строки для работы задачи
                _data.rowBegin = counRow;
 
                // Если не все "лишние строки" посланы в обработку, то добавление одной в создаваемую задачу.
                if (mod-- > 0)
                    _data.length++;
                counRow += _data.length;
 
                // Создание, запуск задачи и запоминание её в массиве
                tasks[num] = Task<int[]>.Factory.StartNew(RowCalk, _data);
            }
 
            // Цикл ожидания завершения каждой задачи.
            while ((tasks = tasks.Where(t => t != null).ToArray()).Length > 0)
            {
                // Обработка возвращённых задачей данных и удаление задачи из массива
                int num = Task.WaitAny(tasks);
                for (int i = 0; i < 511; i++)
                    brightnesCounts[i] += tasks[num].Result[i];
                tasks[num] = null;
            }
 
            // LINQ создающий массив кортежей со статистикой по матрице яркостей.
            (int brightne, int count)[] brightnesCountsSort = brightnesCounts
                .Select((cnt, br) => (brightne: br, count: cnt))
                .Where(pr => pr.count > 0)
                .OrderBy(pr => pr.count)
                .ToArray();
 
 
            return new BrightnesData(brightnes, brightnesCountsSort);
        }
 
        /// <summary>Структура для передачи данных в задачу.</summary>
        struct RowCalkData
        {
            /// <summary>Начальная строка для обработка.</summary>
            public int rowBegin;
            /// <summary>Длина диапазона обрабатываемых строк.</summary>
            public int length;
            /// <summary>Байтовый массив изображения.</summary>
            public byte[] bmpBytes;
            /// <summary>Матрица яркостей.</summary>
            public int[,] brightnes;
        }
 
        // Mетод для расчёта яркостей диапазона строк
        static int[] RowCalk(object obj)
        {
            // Получение структуры данных из нетипизированного параметра
            RowCalkData data = (RowCalkData)obj;
 
            // Ширина изображения
            int width = data.brightnes.GetLength(1);
 
            // Смещение в байтовом массиве
            int k = data.rowBegin * width * 4;
 
            // Строка следующего диапазона - она не должна обрабатываться
            int rowEnd = data.rowBegin + data.length;
 
            // Создание массива статистики по диапазону обрабатываемому в задаче
            int[] brightnesCounts = new int[511];
 
            // Локальные переменные для промежуточного хранения данных в цикле.
            int brightne, r, g, b, min, max;
 
            // Циклы по строкам диапазона и по всем колонкам
            for (int row = data.rowBegin; row < rowEnd; row++)
            {
                for (int col = 0; col < width; col++)
                {
                    // Подсчёт яркости по алгоритму MS
                    r = data.bmpBytes[k++];
                    g = data.bmpBytes[k++];
                    b = data.bmpBytes[k++];
                    min = max = r;
                    if (g > max) max = g;
                    if (b > max) max = b;
 
                    if (g < min) min = g;
                    if (b < min) min = b;
 
                    brightne = min + max;
 
                    // Запоминание яркости и корректировка статистики
                    brightnesCounts[data.brightnes[row, col] = brightne]++;
 
                    k++;
                }
            }
            return brightnesCounts;
        }
 
        /// <summary>Конвертация Матрицы яркости в чёрно белое изображение.</summary>
        /// <param name="data">Матрица яркости и массив статистики.</param>
        /// <param name="part">Доля срезаемых точек от общего их количества.</param>
        /// <returns>Чёрно белое изображение.</returns>
        internal static Bitmap BlackWhiteImage(BrightnesData data, double part)
        {
            // Размеры матрицы
            int height = data.Brightnes.GetLength(0);
            int width = data.Brightnes.GetLength(1);
 
            // Создание байтового массива для изображения
            byte[] argb = new byte[data.Brightnes.Length * 4];
 
            // Уровень срезаемой яркости
            int avbr = 0;
            // Количество срезаемых точек
            double countPixels = 0;
 
            // Цикл по массиву статистики отсортированному по возрастанию яркости
            foreach (var item in data.BrightnesCounts.OrderBy(x => x.brightne))
            {
                // Запоминание яркости
                avbr = item.brightne;
                // Добавление количества точек с этой яркостью
                countPixels += item.count;
 
                // Если количество срезаемых точек превышает заданную долю, то выход из цикла
                if (countPixels / data.Brightnes.Length > part)
                    break;
            }
 
            // Смещение в байтовом массиве
            int k = 0;
 
            // Цикл по всем точкам в массиве яркостей
            foreach (int brightne in data.Brightnes)
            {
                // Если у точки яркость выше определённой, то точка белая
                if (brightne > avbr)
                {
                    argb[k++] = 255;
                    argb[k++] = 255;
                    argb[k++] = 255;
                }
                // Иначе - чёрная
                else
                {
                    argb[k++] = 0;
                    argb[k++] = 0;
                    argb[k++] = 0;
                }
                // Задание байта прозрачности
                argb[k++] = 255;
            }
 
            // Создание нового рисунка с нужным размером и запись в него полученного байтового массива
            var result = new Bitmap(width, height);
            BitmapData bmpData = result.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            int stride = bmpData.Stride;
            System.Runtime.InteropServices.Marshal.Copy(argb, 0, bmpData.Scan0, argb.Length);
            result.UnlockBits(bmpData);
 
            return result;
        }
 
    }
}
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,576
01.10.2020, 01:13
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Но там не синхронизация нужна.
Кстати разницы в производительности не заметил что с синхронизацией, что без.

Результаты тестов:
.NET Framework 4.8 x64 (x86 работает медленнее, и он включен по умолчанию, обязательно отключить)
GetBrightnessSafe 28 мс
GetBrightnessUnsafe 21 мс
GetBrightnessV4 30 мс
GetBrightnessST 412 мс

.NET Core 3.1 x64
GetBrightnessSafe 27 мс
GetBrightnessUnsafe 20 мс
GetBrightnessV4 28 мс
GetBrightnessST 293 мс (тут у .NET Core неплохой выигрыш почему-то)

Видно что Parallel.For (используется в GetBrightnessSafe и GetBrightnessUnsafe) отлично справляется с распределением задачи на несколько потоков автоматически и нет никакой необходимости делать это вручную как сделал Элд Хасп. Да и само API довольно удобное и гибкое.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
01.10.2020, 08:04
Цитата Сообщение от Someone007 Посмотреть сообщение
Parallel.For (используется в GetBrightnessSafe и GetBrightnessUnsafe) отлично справляется с распределением задачи на несколько потоков автоматически
Возможно, есть различия для разных компов.
У меня первый вариант (не помню выкладывал здесь или нет) был с отдельной задачей для каждой строки.
Он был в 2-2,5 раза быстрее чем синхронный.
Потом решил проверить как влияет количество потоков (прочитав пост от Usaga).
Уменьшил до 25 - скорость увеличилась в два раза.
Потом уменьшил до 10 - такая же как при 25.

Но возможно, эти результаты только для старых компов.
Вариант с задачей для каждой строки, по коду значительно проще.
belalugoci, если у него скорость такая же на вашем компе то надо его использовать.

Добавлено через 12 минут
Цитата Сообщение от Someone007 Посмотреть сообщение
Кстати разницы в производительности не заметил что с синхронизацией, что без.
У вас же только финальная блокировка в этих строках?
C#
243
244
245
246
247
248
249
250
251
            static void LocalFinally(LoopData data)
            {
                data.syncLock.EnterWriteLock();
                for (int i = 0; i < 256; i++)
                {
                    data.countsTotal[i] += data.countsLocal[i];
                }
                data.syncLock.ExitWriteLock();
            }
Они очень быстро срабатывают и отдельно для каждого потока..
Просуммировать массив int[511] - это уже не миллисекунды, а микро.
Даже для моего компа.

В конечном варианте вы исправили массив countsTotal на int[511]?

Блокировка оказала бы (возможно) влияние, если бы внутри каждой строки результат сразу накапливался в data.countsTotal без использования буфера data.countsLocal.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
01.10.2020, 08:09  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
если у него скорость такая же на вашем компе то надо его использовать
Не ясно что в этом выводе.
железо i3-4170, 4G RAM
ОС 32-bit Win7
Кликните здесь для просмотра всего текста
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
GetBrightnessSafe
00:00:00.1443447 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1311700 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1287617 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1287214 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1458355 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1381453 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1346685 463 (4, 1) (48, 71944) 9216000 108844
00:00:01.0389317 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1142579 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1184585 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1163453 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1310360 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1194047 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.4203134 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2269095 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2015891 463 (4, 1) (48, 71944) 9216000 108844
00:00:01.7790341 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1429018 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1186036 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1163631 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1229614 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1189234 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1148199 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1209703 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1193337 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1176404 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1234102 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2053791 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1295614 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1171750 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1210210 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1926499 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1155472 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1403833 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1257703 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1162116 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1157692 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1274654 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2149581 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1175567 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1411123 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1160585 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1265819 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1195561 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1161106 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1679128 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1279364 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1981983 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1217239 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1205303 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1930000
GetBrightnesUnsafe
00:00:00.1037104 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1982435 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2119617 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0938302 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0931683 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0982726 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1063331 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1021786 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0972723 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1240607 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0979506 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0971839 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1044063 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1003378 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0994593 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0954649 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1451300 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0951531 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1103533 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1055400 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1017789 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0938324 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0944377 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0962610 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1120202 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1076402 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0970546 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0930704 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0947373 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0936138 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1060177 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0996965 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1010737 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0944499 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0960674 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2398377 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1116488 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0953680 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1066083 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0954665 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0981381 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0961298 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0951803 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0947045 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0956282 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0981350 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0976626 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0933048 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0967123 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.0933206 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1070000
GetBrightnesV4
00:00:00.1396754 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1167966 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2644296 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1334346 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1323783 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1159586 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1163603 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1268321 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1267739 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1207300 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1212618 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1175653 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1347054 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2161181 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1205411 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1192110 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1287667 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1136460 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1209889 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1408305 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1869869 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1398463 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1177414 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1542629 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1212990 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1177803 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1178962 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1285134 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1275486 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1150504 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1256848 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2052055 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1298147 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1384865 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1171969 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1164918 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1178299 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1252382 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1171966 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1136796 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1299844 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1286596 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2169772 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1171575 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1182984 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1330779 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1234585 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1236890 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1189037 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.2000895 463 (4, 1) (48, 71944) 9216000 108844
00:00:00.1350000
GetBrightnessST
00:00:01.8052940 463 (4, 1) (48, 71944) 9216000 108844
00:00:01.7315847 463 (4, 1) (48, 71944) 9216000 108844
00:00:01.6992149 463 (4, 1) (48, 71944) 9216000 108844
00:00:01.7088385 463 (4, 1) (48, 71944) 9216000 108844
00:00:01.7018690 463 (4, 1) (48, 71944) 9216000 108844
00:00:01.7290000


Версия Core у меня не запускается, просит переключиться на preview, но где именно я не найду (MS очень сложно предложить переключить сразу или открыть окно где это можно сделать).

добавил комментариев
Сейчас буду изучать.

Математика!
Чёрт её побери!
Математика как-то проблем не вызывает, я плохо читаю чужой код, особенно если не знаю подробности реализации.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
01.10.2020, 08:20
Цитата Сообщение от belalugoci Посмотреть сообщение
железо i3-4170, 4G RAM
ОС 32-bit Win7
Ну у вас ещё древнее чем у меня...

Добавлено через 4 минуты
Цитата Сообщение от belalugoci Посмотреть сообщение
Сейчас буду изучать.
Теги XML документации удобнее читать при наведении курсора на тип, его член или параметр метода.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
01.10.2020, 08:33  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Ну у вас ещё древнее чем у меня...
Я к древнему еще могу отнести P4 или, с натяжками, Core2Duo, а это железо весьма современное. Новее видел только в аудитории Core i3-8100.
У меня дома ноутбук i5-2520M, ПК i5-3570, собранные совсем недавно.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Теги XML документации удобнее читать при наведении курсора на тип, его член или параметр метода.
Я еще не понял как из форума всё преобразовать в проект в VS. Как раз в процессе.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
01.10.2020, 08:56
Цитата Сообщение от belalugoci Посмотреть сообщение
Я к древнему еще могу отнести...
Это относительная оценка.
Я к тому, что если на моём компе код работал иначе чем у Someone007, то на вашем тоже будет так же.
И методы реализации надо выбирать оптимальные под ваш комп.

Добавлено через 2 минуты
Цитата Сообщение от belalugoci Посмотреть сообщение
Я еще не понял как из форума всё преобразовать в проект в VS. Как раз в процессе.
Создаёте любую форму, заменяете её Cоде Behind на код из моего поста.
Поменять в нём надо только Form1 на название вашей формы.
Это в строке
C#
11
    public partial class Form1 : Form // Здесь вместо Form1 название вашей формы
Добавлено через 17 минут
Размер формы роли не играет.
И она должна быть пустая.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
01.10.2020, 09:04  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
И методы реализации надо выбирать оптимальные под ваш комп
Разве? У меня на работе и дома разное железо, а запускаю и там и там.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Создаёте любую форму, заменяете её Cоде Behind на код из моего поста.
Поменять в нём надо только Form1 на название вашей формы.
Это в строке
Спасибо. Осилил сам. Делфи-стайл помог.

Код в целом работает очень быстро, заметно быстрее того, что было раньше. Еще несколько методов нужно добавить. Пока вижу это как преобразование BrightnesData исходя из потребности. Номером один идёт наложение матрицы шума (dithering), для универсальности файл с шумом лучше передавать как параметр например Bitmap.

Типа такого:
C#
1
internal static BrightnesData BlackWhiteImage(BrightnesData data, Bitmap ditherNoise)
Условием изменения яркости на максимум или минимум является сравнение яркости исходного изображения с яркостью матрицы шума.

Примеры шума во вложении.
Изображения
   
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
01.10.2020, 10:20  [ТС]
Цитата Сообщение от belalugoci Посмотреть сообщение
BrightnesData
я такую логику думаю - зачем постоянно гонять туда-сюда Bitmap, когда можно предварительно всё делать с матрицей яркости, а наборы фильтров потом тасовать как душе угодно - нормализация, квантизация, эквализация и т.п.

Добавлено через 1 час 1 минуту
Цитата Сообщение от belalugoci Посмотреть сообщение
наложение матрицы шума (dithering)
Двигаюсь в этом направлении, первая заготовка
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
        public Form1()
        {
            InitializeComponent();
 
            // Чтение рисунка, его сохранение в поле и вывод на форму.
            pictureBox0.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\e.n.b\Pictures\Deepin\ashim-d-silva-WeYamle9fDM-unsplash.jpg");
 
            // Чтение рисунка шума
            var DithMatrix = (Bitmap)Bitmap.FromFile(@"C:\Users\e.n.b\Pictures\Deepin\photoshop_noise.png");
            if (DithMatrix.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb)
                DithMatrix = To32bpp(DithMatrix);
 
            // Получение матрицы яркости в истинных единицах и массива статистики яркостей
            BrightnesData brightnes = GetBrightnes(ImageSource);
 
            // Получение матрицы яркости с наложением шума
            BrightnesData brightnesDith = DoDithering(brightnes, DithMatrix);
        }
 
        internal static BrightnesData DoDithering(BrightnesData data, Bitmap bmp)
        {
            return data;
        }
 
            private Bitmap To32bpp(Bitmap bmp)
        {
            var res = new Bitmap(bmp.Width, bmp.Height);
            bmp.SetResolution(res.HorizontalResolution, res.VerticalResolution);
            using (var gr = Graphics.FromImage(res))
                gr.DrawImage(bmp, new Point(0, 0));
 
            return res;
        }
Добавлено через 10 минут
Цитата Сообщение от belalugoci Посмотреть сообщение
наложение матрицы шума (dithering)
или даже так
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        public Form1()
        {
            InitializeComponent();
 
            // Чтение рисунка, его сохранение в поле и вывод на форму.
            pictureBox0.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\e.n.b\Pictures\Deepin\ashim-d-silva-WeYamle9fDM-unsplash.jpg");
 
            // Чтение рисунка шума
            var DithMatrix = (Bitmap)Bitmap.FromFile(@"C:\Users\e.n.b\Pictures\Deepin\photoshop_noise.png");
            if (DithMatrix.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb)
                DithMatrix = To32bpp(DithMatrix);
 
            // Получение матрицы яркости в истинных единицах и массива статистики яркостей
            BrightnesData brightnes = GetBrightnes(ImageSource);
 
            // Получение матрицы яркости с наложением шума
            BrightnesData brightnesDith = GetBrightnes(DithMatrix);
            brightnesDith = DoDithering(brightnes, brightnesDith);
 
            // Получение чёрно-белых рисунков из матрицы яркостей с разной долей отсечки точек
            pictureBox1.Image = ImageResult25 = BlackWhiteImage(brightnes, 0.25);
            //pictureBox2.Image = ImageResult50 = BlackWhiteImage(brightnes, 0.5);
            pictureBox3.Image = BlackWhiteImage(brightnesDith, 1.0);
        }
        internal static BrightnesData DoDithering(BrightnesData data, BrightnesData dithData)
        {
            return data;
        }
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,177
Записей в блоге: 2
01.10.2020, 10:52
Цитата Сообщение от belalugoci Посмотреть сообщение
У меня на работе и дома разное железо, а запускаю и там и там.
Я имею вид, что скорости различных методов могут различаться на разных компах.
На одном один быстрее работает, на другом - другой.

Добавлено через 1 минуту
Цитата Сообщение от belalugoci Посмотреть сообщение
я такую логику думаю - зачем постоянно гонять туда-сюда Bitmap, когда можно предварительно всё делать с матрицей яркости, а наборы фильтров потом тасовать как душе угодно - нормализация, квантизация, эквализация и т.п.
Правильно.
У меня же так и сделано.
Матрица яркости создаётся один раз.
А потом в метод среза уже передаётся она, а не исходная картинка.

Добавлено через 37 секунд
Только обратите внимание: Матрица яркости в истинных единицах - это целое число от 0 до 510.

Добавлено через 2 минуты
Цитата Сообщение от belalugoci Посмотреть сообщение
или даже так
Если картина шума не меняется, а меняются только параметры фильтра работающего с матрицами яркости картинки и шума, то этот вариант лучше.

Добавлено через 2 минуты
Цитата Сообщение от belalugoci Посмотреть сообщение
Код в целом работает очень быстро, заметно быстрее того, что было раньше.
Если не трудно напишите время работы метода GetBrightnes для двух-трёх картинок разного размера.
Хочу сравнить с моим компом.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,576
01.10.2020, 12:13
Цитата Сообщение от Элд Хасп Посмотреть сообщение
У вас же только финальная блокировка в этих строках?
Да. Если на каждой итерации синхронизировать то конечно скорость сильно бы упала.
Цитата Сообщение от Элд Хасп Посмотреть сообщение
В конечном варианте вы исправили массив countsTotal на int[511]?
Да там везде размеры заменены на константы.

Цитата Сообщение от belalugoci Посмотреть сообщение
Не ясно что в этом выводе.
Построчно: вариант кода, 50 замеров вызова метода GetBrightness, среднее значение 50 вызовов метода GetBrightness и потом повтор для следующего варианта.
Вот у вас получились средние значения:
GetBrightnessSafe 00:00:00.1930000 - 193 мс, 3 место (вероятно что медленнее из-за автоматического распределения потоков)
GetBrightnesUnsafe 00:00:00.1070000 - 107 мс, 1 место
GetBrightnesV4 00:00:00.1350000 - 135 мс, 2 место (вариант Элд Хасп)
GetBrightnessST 00:00:01.7290000 - 1729 мс, 4 место (однопоточный тест)
Видно что код действительно работает на разном железе с довольно большими различиями...
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
01.10.2020, 13:17  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если не трудно напишите время работы метода GetBrightnes для двух-трёх картинок разного размера.
Хочу сравнить с моим компом.
C#
1
2
3
4
5
6
7
8
9
10
//pictureBox0.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\e.n.b\Pictures\Deepin\ashim-d-silva-WeYamle9fDM-unsplash.jpg");
//pictureBox0.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\e.n.b\Pictures\Deepin\70.jpg"); 
//pictureBox0.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\e.n.b\Pictures\Deepin\ac2ca13a5d9f4ef6bf22722b9417634e.jpg");
pictureBox0.Image = ImageSource = (Bitmap)Image.FromFile(@"C:\Users\e.n.b\Pictures\Deepin\cristina-gottardi-wndpWTiDuT0-unsplash.jpg");
 
Stopwatch sw = new Stopwatch();
 
sw.Restart();
BrightnesData brightnes = GetBrightnes(ImageSource);
sw.Stop();
Время по порядку в коде:
0.2013975
0.0010291
0.0048779
0.1903822

Это значение sw.Elapsed.ToString()
Миниатюры
Добавить к коду подсчет яркостей   Добавить к коду подсчет яркостей   Добавить к коду подсчет яркостей  

Изображения
 
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
01.10.2020, 13:17

Добавить комментарии к коду
нужно прокомментировать код mov ax,@data mov ds,ax mov cx,br mov si,offset mas xor ax, ax c1: xor ax, ax mov al, jmp...

Добавить комментарии к коду
Кто нибудь напишите подробный комментарий к коду ни СИ. Можно подробней по &quot;#define size 5&quot; и int a, a и a. ...

Добавить к коду многоадресный делегат
В иерархии, созданной в этой работе «Интерфейсы», добавить использование для проверки всех методов данного класса многоадресный делегат. ...

К готовому коду добавить процедуру
Суммы элементов каждого столбца матрицы X(m,n), имеющих значения в интервале Min…Max. Для столбца. (К ГОТОВОМУ КОДУ ДОБАВИТЬ ПРОЦЕДУРУ)...

К коду добавить вывод в консоль
Нужно вывести массив в консоль. Как ни пытался, то 0 выводит, то ошибки .586 .model flat,stdcall option casemap:none include...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
100
Ответ Создать тему
Новые блоги и статьи
FPS контроллер с анимированными Y-Bot и 3D-звуком miniaudio (Box3D, Recast, BehaviorTree.CPP, ozz-animation, ImGui, OpenGL и SDL3)
8Observer8 18.10.2026
Содержание блога | English Version Полное мультиплатформенное руководство по стартовому проекту с FPS-контроллером игрока, анимированными роботами Y-Bot с 4-слойным блендингом, 3D-физикой Box3D,. . .
Локальный http сервер
Argus19 17.10.2026
Локальный http сервер На работе, на двух локальных компьютерах круглосуточно работают программы опроса приборов с записью в книги Excel,которые раз в сутки записываются на сервер компании. Т. к. . . .
Копировать Windows на новый диск на UEFI
damix 17.10.2026
https:/ / uriesk. wordpress. com/ 2016/ 11/ 01/ move-window-10-to-ssd-on-a-uefi-dualboot-system-with-basic-linux-tools/ TL DR Вставляем диск, а старый подключаем через переходник, грузимся с лайва. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru