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

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

22.09.2020, 09:49. Показов 7773. Ответов 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
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,576
29.09.2020, 18:46
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вроде устранил все ошибки и добавил возможность задавать количество потоков.
Неправильно считает. Где-то ошибка, но мне лень разбираться.

Вот полный код всех моих тестов. Мой вариант с unsafe (GetBrightnesUnsafe) самый быстрый.
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
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WindowsFormsApp10
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Bitmap bmp = new Bitmap(@"xxx.jpg");
            GetBrightnes(bmp);
            GetBrightnesUnsafe(bmp);
 
            TimeSpan total = TimeSpan.FromSeconds(0);
            Stopwatch sw = new Stopwatch();
            Console.WriteLine("GetBrightnes");
            for (int i = 0; i < 100; i++)
            {
                sw.Restart();
                var result = GetBrightnes(bmp);
                sw.Stop();
                total += sw.Elapsed;
                Console.WriteLine($"{sw.Elapsed} {result.BrightnesCounts.Length} {result.BrightnesCounts[0]} {result.BrightnesCounts[result.BrightnesCounts.Length - 1]} {result.BrightnesCounts.Sum(x => x.count)} {result.BrightnesCounts.Sum(x => x.brightne)}");
            }
            Console.WriteLine(TimeSpan.FromMilliseconds(total.TotalMilliseconds / 100));
 
            total = TimeSpan.FromSeconds(0);
            Console.WriteLine("GetBrightnesUnsafe");
            for (int i = 0; i < 100; i++)
            {
                sw.Restart();
                var result = GetBrightnesUnsafe(bmp);
                sw.Stop();
                total += sw.Elapsed;
                Console.WriteLine($"{sw.Elapsed} {result.BrightnesCounts.Length} {result.BrightnesCounts[0]} {result.BrightnesCounts[result.BrightnesCounts.Length - 1]} {result.BrightnesCounts.Sum(x => x.count)} {result.BrightnesCounts.Sum(x => x.brightne)}");
            }
            Console.WriteLine(TimeSpan.FromMilliseconds(total.TotalMilliseconds / 100));
 
            total = TimeSpan.FromSeconds(0);
            Console.WriteLine("GetBrightnesV3");
            for (int i = 0; i < 100; i++)
            {
                sw.Restart();
                var result = GetBrightnesV3(bmp);
                sw.Stop();
                total += sw.Elapsed;
                Console.WriteLine($"{sw.Elapsed} {result.BrightnesCounts.Length} {result.BrightnesCounts[0]} {result.BrightnesCounts[result.BrightnesCounts.Length - 1]} {result.BrightnesCounts.Sum(x => x.count)} {result.BrightnesCounts.Sum(x => x.brightne)}");
            }
            Console.WriteLine(TimeSpan.FromMilliseconds(total.TotalMilliseconds / 100));
 
            total = TimeSpan.FromSeconds(0);
            Console.WriteLine("GetBrightnesST");
            for (int i = 0; i < 5; i++)
            {
                sw.Restart();
                var result = GetBrightnesST(bmp);
                sw.Stop();
                total += sw.Elapsed;
                Console.WriteLine($"{sw.Elapsed} {result.BrightnesCounts.Length} {result.BrightnesCounts[0]} {result.BrightnesCounts[result.BrightnesCounts.Length - 1]} {result.BrightnesCounts.Sum(x => x.count)} {result.BrightnesCounts.Sum(x => x.brightne)}");
            }
            Console.WriteLine(TimeSpan.FromMilliseconds(total.TotalMilliseconds / 5));
 
            Console.ReadLine();
        }
 
        /// <summary>Преобразует пиксельное цветное изображение в массив in[,] яркостей.</summary>
        /// <param name="bmp">Цветное изображение в формате bmp.</param>
        /// <param name="dev">Коэффициент приведения процентов. Для реальной яркости должен быть равен 100.</param>
        /// <returns>Массив int[,] яркостей пикселей.
        /// Значения яркостей в процентах по отношению к цвету (1, 1, 1) делённое на dev.</returns>
        public static BrightnesData GetBrightnesUnsafe(Bitmap bmp, int dev = 100)
        {
            //Stopwatch stopwatch = new Stopwatch();
            //stopwatch.Start();
 
            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];
            //Marshal.Copy(bmpData.Scan0, bmpBytes, 0, bmpBytes.Length);
            //bmp.UnlockBits(bmpData);
 
            //long timeBytes = stopwatch.ElapsedMilliseconds;
 
            int[,] brightnes = new int[bmp.Height, bmp.Width];
 
            // Y=0.3*R+0.59*G+0.11*B
            //int r = 30, g = 59, b = 11;
            //int k = 0;
            int[] brightnesCounts = new int[256 * 100 / dev];
 
            int height = bmp.Height;
            int width = bmp.Width;
            //Task[] tasks = new Task[height];
            //for (int row = 0; row < height; row++)
            //{
            //    int _row = row;
            //    tasks[row] = Task.Factory.StartNew(rowCalk, _row);
            //}
 
            //Parallel.For(0, height, (i) => rowCalk(i, width, bmpData.Scan0, brightnesCounts, brightnes, dev));
 
            ReaderWriterLockSlim syncLock = new ReaderWriterLockSlim();
 
            Parallel.For(0, height, () => new LoopData { data = brightnes, countsLocal = new int[256], countsTotal = brightnesCounts, syncLock = syncLock }, (a, b, c) => { rowCalk(a, width, bmpData.Scan0, c.countsLocal, c.data, dev); return c; }, LocalFinally);
 
            //Task.WaitAll(tasks);
 
            bmp.UnlockBits(bmpData);
 
            //long timeBrightnes = stopwatch.ElapsedMilliseconds;
 
            (int brightne, int count)[] brightnesCountsSort = brightnesCounts
                .Select((cnt, br) => (brightne: br, count: cnt))
                .Where(pr => pr.count > 0)
                .OrderBy(pr => pr.count)
                .ToArray();
 
            //long timeBrightnesSort = stopwatch.ElapsedMilliseconds;
            return new BrightnesData(brightnes, brightnesCountsSort);
 
            // Локальный метод для расчёта яркостей одной строки
            static void rowCalk(int row, int width, IntPtr scan0, int[] brightnesCounts, int[,] brightnes, int dev)
            {
                int brightne;
                int k = row * width * 4;
 
                const int r = 30, g = 59, b = 11;
 
                unsafe
                {
                    byte* pixelsPtr = (byte*)scan0;
                    for (int col = 0; col < width; col++)
                    {
                        brightne = (r * pixelsPtr[k] + g * pixelsPtr[k + 1] + b * pixelsPtr[k + 2]) / dev;
 
                        brightnes[row, col] = brightne;
                        brightnesCounts[brightne]++;
                        k += 4;
                    }
                }
            }
 
            static void LocalFinally(LoopData data)
            {
                data.syncLock.EnterWriteLock();
                for (int i = 0; i < 256; i++)
                {
                    data.countsTotal[i] += data.countsLocal[i];
                }
                data.syncLock.ExitWriteLock();
            }
        }
 
        /// <summary>Преобразует пиксельное цветное изображение в массив in[,] яркостей.</summary>
        /// <param name="bmp">Цветное изображение в формате bmp.</param>
        /// <param name="dev">Коэффициент приведения процентов. Для реальной яркости должен быть равен 100.</param>
        /// <returns>Массив int[,] яркостей пикселей.
        /// Значения яркостей в процентах по отношению к цвету (1, 1, 1) делённое на dev.</returns>
        public static BrightnesData GetBrightnes(Bitmap bmp, int dev = 100)
        {
            //Stopwatch stopwatch = new Stopwatch();
            //stopwatch.Start();
 
            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];
            Marshal.Copy(bmpData.Scan0, bmpBytes, 0, bmpBytes.Length);
            //bmp.UnlockBits(bmpData);
 
            //long timeBytes = stopwatch.ElapsedMilliseconds;
 
            int[,] brightnes = new int[bmp.Height, bmp.Width];
 
            // Y=0.3*R+0.59*G+0.11*B
            //int r = 30, g = 59, b = 11;
            //int k = 0;
            int[] brightnesCounts = new int[256 * 100 / dev];
 
            int height = bmp.Height;
            int width = bmp.Width;
            //Task[] tasks = new Task[height];
            //for (int row = 0; row < height; row++)
            //{
            //    int _row = row;
            //    tasks[row] = Task.Factory.StartNew(rowCalk, _row);
            //}
 
            //Parallel.For(0, height, (i) => rowCalk(i, width, bmpBytes, brightnesCounts, dev));
 
            ReaderWriterLockSlim syncLock = new ReaderWriterLockSlim();
 
            Parallel.For(0, height, () => new LoopData { data = brightnes, countsLocal = new int[256], countsTotal = brightnesCounts, syncLock = syncLock }, (a, b, c) => { rowCalk(a, width, bmpBytes, c.countsLocal, c.data, dev); return c; }, LocalFinally);
 
            //Task.WaitAll(tasks);
 
            bmp.UnlockBits(bmpData);
 
            //long timeBrightnes = stopwatch.ElapsedMilliseconds;
 
            int numPix = height * width;
            int x = brightnesCounts.Sum();
 
            (int brightne, int count)[] brightnesCountsSort = brightnesCounts
                .Select((cnt, br) => (brightne: br, count: cnt))
                .Where(pr => pr.count > 0)
                .OrderBy(pr => pr.count)
                .ToArray();
 
            //long timeBrightnesSort = stopwatch.ElapsedMilliseconds;
            return new BrightnesData(brightnes, brightnesCountsSort);
 
            // Локальный метод для расчёта яркостей одной строки
            static void rowCalk(int row, int width, byte[] bmpBytes, int[] brightnesCounts, int[,] brightnes, int dev)
            {
                int brightne;
                int k = row * width * 4;
 
                const int r = 30, g = 59, b = 11;
 
                for (int col = 0; col < width; col++)
                {
                    brightne = (r * bmpBytes[k] + g * bmpBytes[k + 1] + b * bmpBytes[k + 2]) / dev;
 
                    brightnes[row, col] = brightne;
                    brightnesCounts[brightne]++;
                    k += 4;
                }
            }
 
            static void LocalFinally(LoopData data)
            {
                data.syncLock.EnterWriteLock();
                for (int i = 0; i < 256; i++)
                {
                    data.countsTotal[i] += data.countsLocal[i];
                }
                data.syncLock.ExitWriteLock();
            }
        }
 
        // Y=0.3*R+0.59*G+0.11*B
        const int R = 30, G = 59, B = 11;
        struct rowCalkData
        {
            public int dev;
            public int rowBegin;
            public int length;
            public byte[] bmpBytes;
            public int[,] brightnes;
            public int[] brightnesCounts;
        }
 
        /// <summary>Преобразует пиксельное цветное изображение в массив in[,] яркостей.</summary>
        /// <param name="bmp">Цветное изображение в формате bmp.</param>
        /// <param name="tasksCount">Количество потоков для расчёта.</param>
        /// <param name="dev">Коэффициент приведения процентов. Для реальной яркости должен быть равен 100.</param>
        /// <returns>Массив int[,] яркостей пикселей.
        /// Значения яркостей в процентах по отношению к цвету (1, 1, 1) делённое на dev.</returns>
        public static BrightnesData GetBrightnesV3(Bitmap bmp, int tasksCount = 10, int dev = 100)
        {
            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[256 * 100 / dev];
 
            int height = bmp.Height;
            int width = bmp.Width;
            Task[] tasks = new Task[tasksCount];
            rowCalkData data = new rowCalkData()
            {
                dev = dev,
                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 + data.length;
                if (mod > 0)
                    _data.rowBegin++;
 
                counRow += _data.rowBegin;
 
                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);
        }
 
        // 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 = 0; row < rowEnd; row++)
            {
                for (int col = 0; col < width; col++)
                {
                    brightne = (R * data.bmpBytes[k] + G * data.bmpBytes[k + 1] + B * data.bmpBytes[k + 2]) / data.dev;
                    data.brightnes[row, col] = brightne;
                    data.brightnesCounts[brightne]++;
                    k += 4;
                }
            }
        }
 
        /// <summary>Преобразует пиксельное цветное изображение в массив in[,] яркостей.</summary>
        /// <param name="bmp">Цветное изображение в формате bmp.</param>
        /// <param name="dev">Коэффициент приведения процентов. Для реальной яркости должен быть равен 100.</param>
        /// <returns>Массив int[,] яркостей пикселей.
        /// Значения яркостей в процентах по отношению к цвету (1, 1, 1) делённое на dev.</returns>
        public static BrightnesData GetBrightnesST(Bitmap bmp, int dev = 100)
        {
            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];
            Marshal.Copy(bmpData.Scan0, bmpBytes, 0, bmpBytes.Length);
            bmp.UnlockBits(bmpData);
 
            int[,] brightnes = new int[bmp.Height, bmp.Width];
 
            // Y=0.3*R+0.59*G+0.11*B
            int r = 30, g = 59, b = 11;
            int brightne;
            int k = 0;
            int[] brightnesCounts = new int[256 * 100 / dev];
            for (int row = 0; row < bmp.Height; row++)
            {
                for (int col = 0; col < bmp.Width; col++)
                {
                    brightne = (r * bmpBytes[k] + g * bmpBytes[k + 1] + b * bmpBytes[k + 2]) / dev;
                    brightnes[row, col] = brightne;
                    brightnesCounts[brightne]++;
                    k += 4;
                }
            }
 
            (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);
        }
    }
 
    public class LoopData
    {
        public int[,] data { get; set; }
        public int[] countsLocal { get; set; }
        public int[] countsTotal { get; set; }
        public ReaderWriterLockSlim syncLock { get; set; }
    }
 
    /// <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;
        }
    }
}
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
29.09.2020, 20:21
Цитата Сообщение от belalugoci Посмотреть сообщение
для будущих преобразований еще нужно картинку BMP представить в виде матрицы яркостей, то есть в коде, где вычисляется яркость, нужно это значение еще ставить в матрицу W*H изображения.
Она возвращается в свойстве data.Brightnes.
Но там яркости в приведённом виде.
Если коэффициент dev=100, то в реальных значениях.
Если dev=1, то в процентах, то есть увеличенное в сто раз значение.

Код можно сильно ускорить, если сделать вставку на Ассемблере.
Но я им не баловался уже больше 20 лет, и мне сейчас это не по силам.

Добавлено через 5 минут
Цитата Сообщение от Someone007 Посмотреть сообщение
Неправильно считает. Где-то ошибка, но мне лень разбираться.
Я одну нашёл, в своём коде исправил, но вы взяли до внесения исправлений.
C#
303
           if (mod-- > 0)
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,576
29.09.2020, 20:26
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Код можно сильно ускорить, если сделать вставку на Ассемблере.
Там уже некуда ускорять, мой вариант с unsafe 27мс занимает, без unsafe 45мс. Ваш который неправильно считает 49мс.
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
29.09.2020, 22:50
Цитата Сообщение от Someone007 Посмотреть сообщение
Там уже некуда ускорять, мой вариант с unsafe 27мс занимает, без unsafe 45мс. Ваш который неправильно считает 49мс.
Ну, на моём стареньком компе цифры совсем иные, раз так в ..цать..
Тестировать все методы мне, наверное, смыла нет.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,576
29.09.2020, 22:55
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Ну, на моём стареньком компе цифры совсем иные, раз так в ..цать..
Ну многопоточный вариант очень сильно скалируется от железа. У меня 8 ядер/16 потоков.
На однопоточном бы разница была гораздо меньше (у меня ~623мс GetBrightnesST выполняется, но он вроде не особо оптимизирован даже для однопотока).
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
29.09.2020, 22:57
Цитата Сообщение от Someone007 Посмотреть сообщение
у меня ~623мс GetBrightnesST выполняется
У меня однопоточные варианты на картинке 1500х1100 выполнялись 600-900 мс.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
30.09.2020, 05:52  [ТС]
Ошибка CS0227 Небезопасный код может использоваться только при компиляции с параметром /unsafe.
Гайды, что читаю по тому, где такое настраивать, ведут в Обозреватель решений на вкладку Сборка, но у меня в Обозревателе вкладок нет.

Ошибка CS0029 Не удается неявно преобразовать тип "WindowsFormsApp1.Form1.BrightnesData" в "System.Drawing.Image". WindowsFormsApp1
Для рисования на форме требуется преобразование к другому типу.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
30.09.2020, 07:20  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Тестировать
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
            internal static Bitmap Process2(Bitmap bmp)
            {
                var result = new Bitmap(bmp.Width, bmp.Height);
                var ditheringMatrix = Resources.Dithering64x64;
                var source = GetBrightnes(bmp);
                using (var res = new ImageWrapper(result))
                using (var dith = new ImageWrapper(ditheringMatrix))
                {
                    Point p = new Point();
                    for(int w = 0; w < bmp.Width; w++)
                        for(int h = 0; h < bmp.Height; h++)
                        {
                            var dithPixel = dith[w % dith.Width, h % dith.Height].GetBrightness();
                            float pixel = source.Brightnes[h, w] / 100.0F;
                            p.X = w;
                            p.Y = h;
                            if (pixel >= dithPixel)
                                res.SetPixel(p, 255, 255, 255);
                            else
                                res.SetPixel(p, 0, 0, 0);
                        }
                }
                return result;
            }
Пока написал так float pixel = source.Brightnes[h, w] / 100.0F; если написать [w, h], как по идее и должно быть, то индекс уходит за границу. Но в таком варианте рисует только одну строку размерности bmp.Width*ditheringMatrix.Height.
Собственно этот кусок кода мне нужен для отрисовки изображения на форме. Кстати ваша яркость отличается от яркости ImageWrapper в большую сторону и заметно искажает изображение.
Миниатюры
Добавить к коду подсчет яркостей   Добавить к коду подсчет яркостей  
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
30.09.2020, 08:08
Цитата Сообщение от belalugoci Посмотреть сообщение
Кстати ваша яркость отличается от яркости ImageWrapper в большую сторону и заметно искажает изображение.
У ImageWrapper нет метода получения яркости.
Он только возвращает цвет пикселя в типе Color.
Метод GetBrightness относится к методу типа Color.

Добавлено через 11 минут
Я не работал с изображениями.
Формулу яркости взял из инета.
Есть в нескольких источниках.
Всюду одинаковая.
Но MS любительница вставить что-то своё.
Делает так для отсутствия совместимости, чтобы вынуждены были пользоваться только её ПО.

Попробую разобраться.

Добавлено через 18 минут
Так и есть!
MS как всегда "отличилась":
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        public float GetBrightness() {
            float r = (float)R / 255.0f;
            float g = (float)G / 255.0f;
            float b = (float)B / 255.0f;
 
            float max, min;
 
            max = r; min = r;
 
            if (g > max) max = g;
            if (b > max) max = b;
 
            if (g < min) min = g;
            if (b < min) min = b;
 
            return(max + min) / 2;
        }
Добавлено через 2 минуты
Проверка:
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
        public static float GetBrightness(int R, int G, int B)
        {
            float r = (float)R / 255.0f;
            float g = (float)G / 255.0f;
            float b = (float)B / 255.0f;
 
            float max, min;
 
            max = r; min = r;
 
            if (g > max) max = g;
            if (b > max) max = b;
 
            if (g < min) min = g;
            if (b < min) min = b;
 
            return (max + min) / 2;
        }
        static void Main(string[] args)
        {
            Random rnd = new Random();
            for (int i = 0; i < 20; i++)
            {
                int r = rnd.Next(255);
                int g = rnd.Next(255);
                int b = rnd.Next(255);
  
                Color c = Color.FromArgb(r, g, b);
 
                var br = c.GetBrightness();
                var brg = GetBrightness(r, g, b);
 
                Console.WriteLine($"{br} {brg}");
            }
Консоль0,4490196 0,4490196
0,4411765 0,4411765
0,4745098 0,4745098
0,5823529 0,5823529
0,6019608 0,6019608
0,6137255 0,6137255
0,3803922 0,3803922
0,4196078 0,4196078
0,7392157 0,7392157
0,6313726 0,6313726
0,7313725 0,7313726
0,7352941 0,7352941
0,4627451 0,4627451
0,7235294 0,7235294
0,4588235 0,4588235
0,3529412 0,3529412
0,4843137 0,4843137
0,1921569 0,1921569
0,5352941 0,5352941
0,3470588 0,3470588


Сейчас подправлю методы под вариант MS.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
30.09.2020, 08:53
belalugoci, вот исправленные под MS коды
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
        /// <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 + data.length;
                if (mod-- > 0)
                    _data.rowBegin++;
 
                counRow += _data.rowBegin;
 
                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 = 0; 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++;
                }
            }
 
        }
        static void Main(string[] args)
        {
 
            Stopwatch stopwatch = new Stopwatch();
 
            Bitmap bmp = (Bitmap)Image.FromFile(@"C:\Users\EldHa\OneDrive\Изображения\FlatEarthMap.bmp");
 
            stopwatch.Start();
            var brightnes = GetBrightnes(bmp, 8);
            stopwatch.Stop();
 
            Console.WriteLine($"Минимальное количество точек с одной яркостью: {brightnes.BrightnesCounts[0]}");
            Console.WriteLine($"Максимальное количество точек с одной яркостью: {brightnes.BrightnesCounts[brightnes.BrightnesCounts.Length - 1]}");
            Console.WriteLine($"Количество различных яркостей: {brightnes.BrightnesCounts.Length}");
            Console.WriteLine("Список яркостей яркостей в порядке возрастания их количества");
            Console.WriteLine(string.Join(Environment.NewLine, brightnes.BrightnesCounts));
Добавлено через 7 минут
Цитата Сообщение от belalugoci Посмотреть сообщение
internal static Bitmap Process2(Bitmap bmp)
Что делает этот метод?
Не по алгоритму, а простыми словами его смысл.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
30.09.2020, 09:43  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Что делает этот метод?
Не по алгоритму, а простыми словами его смысл.
сканирует яркости пикселей оригинального изображения (реализовано), производит трансформацию исходя из определенного алгоритма (не реализовано), формирует выходной битмап (реализовано).
то есть обрабатывает картинку каким-то алгоритмом (например нормализация гистограммы) и показывает на форме результат.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
30.09.2020, 10:24  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
вот исправленные под MS коды
Стало еще ярче
Миниатюры
Добавить к коду подсчет яркостей  
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
30.09.2020, 10:34
Цитата Сообщение от belalugoci Посмотреть сообщение
сканирует яркости .... и показывает на форме результат.
По-моему вот так будет получение чёрно белого:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        internal static Bitmap Process2(Bitmap bmp)
        {
            var result = new Bitmap(bmp.Width, bmp.Height);
            var source = GetBrightnes(bmp);
            using (var res = new ImageWrapper(result))
            {
                Point p = new Point();
                for (int w = 0; w < bmp.Width; w++)
                    for (int h = 0; h < bmp.Height; h++)
                    {
                        byte brightne = (byte)(source.Brightnes[h, w] / 2);
                        p.X = w;
                        p.Y = h;
                        res.SetPixel(p, brightne, brightne, brightne);
                    }
            }
            return result;
        }
Добавлено через 5 минут
Цитата Сообщение от belalugoci Посмотреть сообщение
Стало еще ярче
Вы на Формах выводите?
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
30.09.2020, 10:48  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
По-моему вот так будет получение чёрно белого
почему (source.Brightnes[h, w] / 2) деление на 2?

[h, w] почему на 90 градусов повернуто?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
res.SetPixel(p, brightne, brightne, brightne);
Градации серого?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вы на Формах выводите?
pictureBox1.Image
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
30.09.2020, 11:48
Цитата Сообщение от belalugoci Посмотреть сообщение
почему (source.Brightnes[h, w] / 2) деление на 2?
Это из реализации MS метода GetBrightness().
Посмотрите в посте MS как всегда "отличилась": что возвращает метод.

Цитата Сообщение от belalugoci Посмотреть сообщение
[h, w] почему на 90 градусов повернуто?
Может где-то перепутал координаты.
Я не отлаживал метод на вывод.
Только на ошибки компиляции.

Добавлено через 14 секунд
Цитата Сообщение от belalugoci Посмотреть сообщение
Градации серого?
Да.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
30.09.2020, 12:04  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Это из реализации MS метода GetBrightness()
а оно не должно быть внутри метода?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Да.
это не нужно, градации внутри data.Brightnes, а картинка 1 бит (лазерный гравёр).
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
30.09.2020, 12:07
Цитата Сообщение от belalugoci Посмотреть сообщение
[h, w] почему на 90 градусов повернуто?
В C# принято сначала цикл по строкам (по высоте), а потом вложенный в него цикл по колонам (по ширине).

Добавлено через 1 минуту
Цитата Сообщение от belalugoci Посмотреть сообщение
это не нужно, градации внутри data.Brightnes, а картинка 1 бит (лазерный гравёр).
Это для изображения.
А для одного бита наверное надо выбрать какой-то уровень и по нему резать.
Выше - 255, ниже - 0.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
30.09.2020, 13:33  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
В C# принято сначала цикл по строкам (по высоте), а потом вложенный в него цикл по колонам (по ширине).
спорить не стану, не обращал внимания, но всегда в коде или Col, Row или Width, Height, и то и другое эквивалентно X, Y или Столбец, Строка.

Добавлено через 50 секунд
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Это для изображения.
А для одного бита наверное надо выбрать какой-то уровень и по нему резать.
Выше - 255, ниже - 0.
Не понял.

Добавлено через 1 час 18 минут
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
            internal static Bitmap Process2(Bitmap bmp)
            {
                var result = new Bitmap(bmp.Width, bmp.Height);
                var dith = GetBrightnes(Resources.Dithering64x64);
                var source = GetBrightnes(bmp);
                using (var res = new ImageWrapper(result))
                {
                    Point p = new Point();
                    for(int w = 0; w < bmp.Width; w++)
                        for(int h = 0; h < bmp.Height; h++)
                        {
                            float dithPixel = dith.Brightnes[w % Resources.Dithering64x64.Width, h % Resources.Dithering64x64.Height] / 2.0F;
                            float     pixel = source.Brightnes[h, w] / 2.0F;
                            p.X = w;
                            p.Y = h;
                            if (pixel >= dithPixel)
                                res.SetPixel(p, 255, 255, 255);
                            else
                                res.SetPixel(p, 0, 0, 0);
                        }
                }
                return result;
            }
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
            internal static Bitmap Process3(Bitmap bmp)
            {
                var result = new Bitmap(bmp.Width, bmp.Height);
                var source = GetBrightnes(bmp);
                using (var res = new ImageWrapper(result))
                {
                    Point p = new Point();
                    for (int w = 0; w < bmp.Width; w++)
                        for (int h = 0; h < bmp.Height; h++)
                        {
                            byte brightne = (byte)(source.Brightnes[h, w] / 2);
                            p.X = w;
                            p.Y = h;
                            res.SetPixel(p, brightne, brightne, brightne);
                        }
                }
                return result;
            }
Porcess3 работает, не глючит. В Process2 добавляю Dithering, приложение не финализируется, картинки не выводятся, ошибок не сообщает.

Добавлено через 4 минуты
Цитата Сообщение от belalugoci Посмотреть сообщение
Process2
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
            internal static Bitmap Process2(Bitmap bmp)
            {
                var result = new Bitmap(bmp.Width, bmp.Height);
                var dith = GetBrightnes(Resources.Dithering64x64);
                var source = GetBrightnes(bmp);
                using (var res = new ImageWrapper(result))
                {
                    Point p = new Point();
                    for(int w = 0; w < bmp.Width; w++)
                        for(int h = 0; h < bmp.Height; h++)
                        {
                            byte dithPixel = (byte) (dith.Brightnes[w % Resources.Dithering64x64.Width, h % Resources.Dithering64x64.Height] / 2);
                            byte     pixel = (byte) (source.Brightnes[h, w] / 2);
                            p.X = w;
                            p.Y = h;
                            if (pixel >= dithPixel)
                                res.SetPixel(p, 255, 255, 255);
                            else
                                res.SetPixel(p, 0, 0, 0);
                        }
                }
                return result;
            }
можно и так
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
30.09.2020, 13:35
Цитата Сообщение от belalugoci Посмотреть сообщение
спорить не стану, не обращал внимания, но всегда в коде или Col, Row или Width, Height, и то и другое эквивалентно X, Y или Столбец, Строка.
Координаты задаются (X, Y), а адрес элемента (Row, Column).
И здесь действительно есть противоречие между ними.
Для точки задаётся сначала координата по горизонтали, а для матрицы - по вертикале (строка).

Матрица пикселей также адресуется как любая другая матрица: сначала строка, потом колонка.
Так же организуются цикля для многомерных массивов: первый цикл по первому индексу, второй по второму и т.д.

Это ещё связанно и с платформой Net и архитектурой x86.
Массивы в памяти хранятся в порядке изменения младших индексов.
То есть для матрицы - построчно.
0
 Аватар для belalugoci
475 / 294 / 29
Регистрация: 01.06.2018
Сообщений: 3,676
30.09.2020, 13:42  [ТС]
Цитата Сообщение от belalugoci Посмотреть сообщение
приложение не финализируется, картинки не выводятся, ошибок не сообщает
C#
1
2
3
4
5
int     dw = Resources.Dithering64x64.Width;
int     dh = Resources.Dithering64x64.Height;
using (var res = new ImageWrapper(result))
...
byte dithPixel = (byte) (dith.Brightnes[h % dh, w % dw] / 2);
Перед using переменные ввёл и ниже их использовал, стало работать и рисовать, но всякую ерунду.
Миниатюры
Добавить к коду подсчет яркостей  
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
30.09.2020, 13:42

Добавить комментарии к коду
нужно прокомментировать код 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...


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

Или воспользуйтесь поиском по форуму:
80
Ответ Создать тему
Новые блоги и статьи
GitHub Copilot в JetBrains: модель по умолчанию, Fix и контроль MCP
and_y87 12.10.2026
10 октября 2026 года GitHub обновил Copilot для JetBrains: добавил настройки стартовой модели, исправления из диагностики и управление автозапуском MCP. Поддержка IDE 2025. 1 прекращена — требуется. . .
День 5 из 28: Codex подсказывает следующий запрос
and_y87 12.10.2026
9 октября 2026 года OpenAI запустила бету Composer predictions — подсказок следующего сообщения в текущем диалоге Codex. Это помощь с формулировкой запроса, а не автоматическое продолжение задачи. . . .
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
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