Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
0 / 0 / 0
Регистрация: 04.10.2019
Сообщений: 16

Создание линии на фотографии

05.03.2020, 22:45. Показов 1635. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый вечер, форумчане!
Появилась необходимость нарисовать линию в чёрно-белой фотографии с использованием сглаживания, откапал я вот такой вот алгоритм. ТЫК!

Но в этом алгоритме идёт отрисовка в новое окно, а мне нужно выводить в двумерный массив. Крутил, вертел, но не работает, как мне нужно.
Сижу уже довольно длительное время.
Хелм ми плиз

Реализация:
Кликните здесь для просмотра всего текста

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
#include <SDL.h>
#include <iostream>
 
using namespace std;
 
  
// SDL материал
SDL_Window* pWindow = 0;
SDL_Renderer* pRenderer = 0;
 
// меняет два числа
void swap(int* a , int*b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
// возвращает абсолютное значение числа
float absolute(float x )
{
    if (x < 0) return -x;
    else return x;
}
// возвращает целую часть числа с плавающей точкой
int iPartOfNumber(float x)
{
    return (int)x;
}
// округляет число
int roundNumber(float x)
{
    return iPartOfNumber(x + 0.5) ;
}
// возвращает дробную часть числа
float fPartOfNumber(float x)
{
    if (x>0) return x - iPartOfNumber(x);
    else return x - (iPartOfNumber(x)+1);
}
// возвращает 1 - дробная часть числа
float rfPartOfNumber(float x)
 
{
    return 1 - fPartOfNumber(x);
}
// рисует пиксель на экране заданной яркости
// 0 <= яркость <= 1. Мы можем использовать вашу собственную библиотеку
// рисовать на экране
void drawPixel( int x , int y , float brightness)
 
{
    int c = 255*brightness;
 
    SDL_SetRenderDrawColor(pRenderer, c, c, c, 255);
 
    SDL_RenderDrawPoint(pRenderer, x, y);
}
void drawAALine(int x0 , int y0 , int x1 , int y1)
{
    int steep = absolute(y1 - y0) > absolute(x1 - x0) ;
    // меняем координаты, если наклон> 1 или мы
    // рисовать задом наперед
    if (steep)
    {
 
        swap(&x0 , &y0);
 
        swap(&x1 , &y1);
 
    }
    if (x0 > x1)
    {
 
        swap(&x0 ,&x1);
 
        swap(&y0 ,&y1);
 
    }
    
    // вычислить наклон
    float dx = x1-x0;
    float dy = y1-y0;
    float gradient = dy/dx;
    
    if (dx == 0.0)
        gradient = 1;
    int xpxl1 = x0;
    int xpxl2 = x1;
    float intersectY = y0;
    // основной цикл
    if (steep)
    {
        int x;
        for (x = xpxl1 ; x <=xpxl2 ; x++)
        {
            // покрытие пикселей определяется дробным
            // часть координаты y
            drawPixel(iPartOfNumber(intersectY), x,
                        rfPartOfNumber(intersectY));
            drawPixel(iPartOfNumber(intersectY)-1, x,
                        fPartOfNumber(intersectY));
            intersectY += gradient;
        }
    }
    else
    {
 
        int x;
 
        for (x = xpxl1 ; x <=xpxl2 ; x++)
        {
 
            // покрытие пикселей определяется дробным
 
            // часть координаты y
 
            drawPixel(x, iPartOfNumber(intersectY),
 
                        rfPartOfNumber(intersectY));
 
            drawPixel(x, iPartOfNumber(intersectY)-1,
 
                          fPartOfNumber(intersectY));
 
            intersectY += gradient;
 
        }
    }
}
 
int main(int argc, char* args[])
{
    SDL_Event event;
    // инициализируем SDL
    if (SDL_Init(SDL_INIT_EVERYTHING) >= 0)
    {
 
        // если удалось создать наше окно
 
        pWindow = SDL_CreateWindow("Anti-Aliased Line ",
 
                     SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
 
                                                          640, 480,
 
                                                  SDL_WINDOW_SHOWN);
 
  
 
        // если создание окна прошло успешно, создайте наш рендерер
 
        if (pWindow != 0)
 
            pRenderer = SDL_CreateRenderer(pWindow, -1, 0);
 
    }
    else
        return 1; // sdl не смог инициализировать
    while (1)
    {
        if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
            break;
        // Устанавливает цвет фона на белый
        SDL_SetRenderDrawColor(pRenderer, 255, 255, 255, 255);
        SDL_RenderClear(pRenderer);
        // рисует черный AALine
        drawAALine(80 , 200 , 550, 150);
        // показать окно
        SDL_RenderPresent(pRenderer);
    }
    // очищаем SDL
    SDL_Quit();
    return 0;
}
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
05.03.2020, 22:45
Ответы с готовыми решениями:

Создание базы данных по фотографии 201х161
Моей девчонки задали сделать базу с условиями. Я уже закалибался, тупо не хватает фантазии помогите кто может!!! Там на фото где маленькие...

Скрытый опрос по фотографии. Анонимный комментарий для фотографии
Ребят такая проблема, не могу разобраться как сделать. задача такая есть детские фотографии пользователям нужно отгадать кто на ней...

Выравнивание картинки в html и создание кликабельных ссылок на самой фотографии
Добрый день уважаемые форумчане, подскажите пожалуйста что мне нужно изменить в html коде страницы что бы картинка на ней нормально...

9
2736 / 891 / 331
Регистрация: 10.02.2018
Сообщений: 2,118
06.03.2020, 18:29
Цитата Сообщение от I-E-X Посмотреть сообщение
Хелм ми плиз
Да, данный алгоритм не очень подойдёт. Если линия будет проходить по темному фону, то по границе линии появятся светлые вкрапления. При определении цвета нужно учитывать цвет фонового пикселя под рисуемым. Можно трактовать яркость рисуемого пикселя (аргумент brightness в функции drawPixel) не как яркость, а как прозрачность. Если яркость близка к 0 (чёрный), то прозрачность минимальная и цвет фона почти не влияет на результат. Если яркость близка к 1 (белый), то прозрачность максимальна и цвет линии почти не изменяет фона. С SDL-ем не знаком, но чисто интуитивно:
C++
1
2
3
4
5
6
7
8
9
10
11
void drawPixel( int x , int y , float brightness)
{
    // желаемый цвет линии (оставить 0 для черной)
    int r = 0;
    int g = 0;
    int b = 0;
 
    SDL_SetRenderDrawColor(pRenderer, r, g, b, 255*(1-brightness));
 
    SDL_RenderDrawPoint(pRenderer, x, y);
}
1
0 / 0 / 0
Регистрация: 04.10.2019
Сообщений: 16
06.03.2020, 20:16  [ТС]
В том, то и прикол, что мне не нужен SDL, мне нужно изменённые пиксели вывести в двумерный массив. (+ у меня только чёрное-белое фото, поэтому r = g = b )
Но если я, например, делаю так:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
void drawPixel(uint8_t **&mas, int x , int y , float brightness)
{
uint8_t c = 255*(1-brightness);
mas[x][y] = c;
}

То не работает, ничего

Добавлено через 8 минут
Ygg
0
2736 / 891 / 331
Регистрация: 10.02.2018
Сообщений: 2,118
06.03.2020, 21:57
Цитата Сообщение от I-E-X Посмотреть сообщение
В том, то и прикол, что мне не нужен SDL, мне нужно изменённые пиксели вывести в двумерный массив.
Хорошо, а как и где вы берёте исходные (не изменённые) пиксели?
Как вы открываете картинку и чем она представлена в программе, массив, битмэп или объект какой-то?
1
06.03.2020, 22:07

Не по теме:

Цитата Сообщение от I-E-X Посмотреть сообщение
uint8_t **
Не надо так, загружайте одномерный массив пикселей.

0
0 / 0 / 0
Регистрация: 04.10.2019
Сообщений: 16
06.03.2020, 22:29  [ТС]
zayats80888,
Да хоть, одномерный, хоть двумерный. Как их оттуда вывести? У меня алгоритм не хочет работать с массивами (((

Добавлено через 3 минуты
Ygg,
пнм формат, п5. Там пиксели идут в виде байтов у которых значение от 0 до 255. (черный -> белый)
Я их считываю в массив и передаю в алгоритм. Способом который описан выше.
0
2736 / 891 / 331
Регистрация: 10.02.2018
Сообщений: 2,118
07.03.2020, 01:27
Если у вас есть одномерный массив, то, скорее всего, пиксели лежат построчно. Предположим, ширина картинки CX. Тогда первая строка картинки - это байты с индексами от 0 до CX. Вторая строка - байты с индексами от CX до 2*CX и так далее. Тогда функцию для рисования пикселя можно представить как-то так:
C++
1
2
3
4
void drawPixel(uint8_t* mas, int x , int y , float brightness)
{
  mas[x + y*CX] = mas[x + y*CX] * brightness;
}
1
0 / 0 / 0
Регистрация: 04.10.2019
Сообщений: 16
07.03.2020, 04:49  [ТС]
Ygg,
Не работает, как надо. Он рисует просто линию без сглаживания, а в нём вся соль.
0
736 / 700 / 110
Регистрация: 29.05.2015
Сообщений: 4,282
07.03.2020, 08:42
Вот два рисунка линий, с сглаживанием и без. Смотри как это реализуется и делай так же:
Изображения
  
1
2736 / 891 / 331
Регистрация: 10.02.2018
Сообщений: 2,118
07.03.2020, 16:47
Лучший ответ Сообщение было отмечено I-E-X как решение

Решение

Цитата Сообщение от I-E-X Посмотреть сообщение
Не работает, как надо. Он рисует просто линию без сглаживания, а в нём вся соль.
В чём это выражается?
"Нарисовал" вашим кодом линию. Явно видно, что есть значения отличные от белого (FF) и чёрного (00).
Код
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
#include <stdio.h>
 
#define CX 8
#define CY 6
 
unsigned char mas[CX*CY];
 
// меняет два числа
void swap(int* a, int* b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
 
// возвращает абсолютное значение числа
float absolute(float x)
{
    if (x < 0) return -x;
    else return x;
}
 
// возвращает целую часть числа с плавающей точкой
int iPartOfNumber(float x)
{
    return (int)x;
}
 
// округляет число
int roundNumber(float x)
{
    return iPartOfNumber(x + 0.5);
}
 
// возвращает дробную часть числа
float fPartOfNumber(float x)
{
    if (x > 0) return x - iPartOfNumber(x);
    else return x - (iPartOfNumber(x) + 1);
}
 
// возвращает 1 - дробная часть числа
float rfPartOfNumber(float x)
{
    return 1 - fPartOfNumber(x);
}
 
// рисует пиксель на экране заданной яркости
// 0 <= яркость <= 1. Мы можем использовать вашу собственную библиотеку
// рисовать на экране
void drawPixel(int x, int y, float brightness)
{
    mas[x + y * CX] = mas[x + y * CX] * brightness;
}
 
void drawAALine(int x0, int y0, int x1, int y1)
{
    int steep = absolute(y1 - y0) > absolute(x1 - x0);
    // меняем координаты, если наклон> 1 или мы
    // рисовать задом наперед
    if (steep)
    {
        swap(&x0, &y0);
        swap(&x1, &y1);
    }
    if (x0 > x1)
    {
        swap(&x0, &x1);
        swap(&y0, &y1);
    }
 
    // вычислить наклон
    float dx = x1 - x0;
    float dy = y1 - y0;
    float gradient = dy / dx;
 
    if (dx == 0.0)
        gradient = 1;
    int xpxl1 = x0;
    int xpxl2 = x1;
    float intersectY = y0;
    // основной цикл
    if (steep)
    {
        int x;
        for (x = xpxl1; x <= xpxl2; x++)
        {
            // покрытие пикселей определяется дробным
            // часть координаты y
            drawPixel(iPartOfNumber(intersectY), x,
                rfPartOfNumber(intersectY));
            drawPixel(iPartOfNumber(intersectY) - 1, x,
                fPartOfNumber(intersectY));
            intersectY += gradient;
        }
    }
    else
    {
        int x;
 
        for (x = xpxl1; x <= xpxl2; x++)
        {
            // покрытие пикселей определяется дробным
            // часть координаты y
            drawPixel(x, iPartOfNumber(intersectY),
            rfPartOfNumber(intersectY));
            drawPixel(x, iPartOfNumber(intersectY) - 1,
            fPartOfNumber(intersectY));
            intersectY += gradient;
        }
    }
}
 
void showMas(const char* msg)
{
    printf("%s\n", msg);
    for (int y = 0; y < CY; y++)
    {
        for (int x = 0; x < CX; x++)
            printf("%02X ", mas[x + y * CX]);
        printf("\n");
    }
}
 
int main(int argc, char* args[])
{
    for (int i = 0; i < CX * CY; i++)
        mas[i] = 255;
 
    showMas("before:");
 
    drawAALine(1, 1, CX - 1, CY - 1);
    
    showMas("after:");
 
    return 0;
}

Результат:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
before:
FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF
 
after:
FF 00 AA FF FF FF FF FF
FF FF 54 55 FF FF FF FF
FF FF FF A9 00 AA FF FF
FF FF FF FF FE 54 55 FF
FF FF FF FF FF FF A9 00
FF FF FF FF FF FF FF FF
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
07.03.2020, 16:47
Помогаю со студенческими работами здесь

Создание 2 линии
Имеется 2 линии на которых бригады используют единственный кран штабелер . Но и другая бригада забирает его через каждые 39+/-10 мин. Как...

Создание линии!
Доброго дня всем! Подскажите как такое сделать: Нажимаю на кнопку мыши и не отпускаю и рисуется линия в произвольном виде т.е куда мышь...

Создание произвольной линии
Здравствуйте. У меня возникла проблема: Требуется на квадратном поле (скорее всего буду пользоваться tkinter.Canvas) создать замкнутую...

Создание буфера линии
Здравствуйте! Существует такая задача: необходимо создать буфер для прямой линии, для которой известны точки начала и конца. Буфер -...

создание линии тренда
Всем доброго времени суток! подскажите пожалуйста, в общем проект импортирует таблицу из Exsel и по ней строит график, нужно построить...


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
Программный контроль заполнения реквизита табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать контроль заполнения реквизита "ПричинаСписания". . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
Программная установка даты и запрет ее изменения
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: при создании документов установить период списания автоматически. . .
Вывод данных в справочнике через динамический список
Maks 01.04.2026
Реализация из решения ниже выполнена на примере нетипового справочника "Спецтехника" разработанного в конфигурации КА2. Задача: вывести данные из ТЧ нетипового документа. . .
Программное заполнения текстового поля в реквизите формы документа
Maks 01.04.2026
Алгоритм из решения ниже реализован на нетиповом документе "ВыдачаОборудованияНаСпецтехнику" разработанного в конфигурации КА2, в дополнении к предыдущему решению. На форме документа создается. . .
К слову об оптимизации
kumehtar 01.04.2026
Вспоминаю начало 2000-х, университет, когда я писал на Delphi. Тогда среди программистов на форумах активно обсуждали аккуратную работу с памятью: нужно было следить за переменными, вовремя. . .
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
Модель здравосоХранения 6. ESG-повестка и устойчивое развитие; углублённый анализ кадрового бренда
anaschu 31.03.2026
В прикрепленном документе раздумья о том, как можно поменять модель в будущем
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru