Программа для оцифровки графиков, чертежей, рисунков

Программа для оцифровки графиков, чертежей, рисунков Статьи

Вступительное слово

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

Для того, чтобы получить данные, нужно “оцифровать” такой график (или графический объект), другими словами, нужно получить набор абсцисс и ординат точек графика — далее над ними можно будет производить различные манипуляции: построить новый (качественный) график, производить вычисления, переведя его в новый формат (например, построив сплайн) и пр.

В своих проектах я встречался с этой проблемой в двух основных видах:

  • “оцифровка” графика для того, чтобы сделать его соответствующим нашему стилю или просто сделать так, чтобы он выглядел прилично;
  • получение набора базовых точек для построения геометрических чертежей, гистограмм и пр. на основе авторского рисунка от руки (или с использованием простейших графических систем).

В этом посте приведен код созданной для этого функции graphicsDigitizing, а также кратко рассказывается о том, как она устроена. Также можно посмотреть как она работает вживую.

Принцип работы

Работа программы довольно проста. Необходимо поместить цифровую иллюстрацию (скан, фото, скриншот, другая картинка) на некоторое поле на “первый” слой. Далее выполняется еёручная обработка:

  • подбор рабочей области (прямоугольник) с заданием “реальных” координат его левой нижней и правой верхней вершины — другими словами области определения и значений той функции (графика, набора точек), который мы получим в результате;
  • простановка опорных точек, по которым будет построен B-сплайн заданной степени;
  • предпросмотр результата;
  • вывод результата в вычисляемом виде для дальнейшей работы.

Мы выбрали B-сплайны по нескольким причинам:

  • они дают гибкие кривые (если степень B-сплайна выше 1-й),
  • дают компактные аналитические представления кривых (кривые Безье — это вырожденный случай B-сплайнов, в которых каждая точка, если говорить просто, влияет на весь вид кривой);
  • просты в работе (реализованы во многих пакетах и не так сложны, если их потребуется запрограммировать с нуля самостоятельно).

На рисунке ниже показан набор точек (опорные точки), набор B-сплайнов 1-й, 2-й и 3-й степеней, а также кривая Безье (в показанной случае это по сути B-сплайн 7-й степени).

Программа для оцифровки графиков, чертежей, рисунков

Для создания программы оцифровки графиков — как и для многих других задач — мы используем язык Wolfram Language.

Описание программы

Конечно, мы не будем описывать, как работает по шагам весь код программы, представленной ниже, это было бы очень долго и, как нам кажется, тех, кого заинтересует рассматриваемый вопрос или, более того, тех перед кем он остро стоит — сами смогут разобраться во всех “винтиках” кода, благо, он краток.

Мы же обратим внимание на его главные элементы.

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

CompoundExpression, ClearAll, SetDelayed, Optional, Pattern, Blank, Image, ImageResize, List, Rule, ColorSpace, With, Set, ImageDimensions, CreateDialog, ExpressionCell, DynamicModule, Grid, DefaultButton, DialogReturn, If, Less, Length, None, Drop, Transpose, Part, Span, ReplaceAll, Rescale, All, Min, Max, RuleDelayed, Real, Round, CopyToClipboard, BSplineCurve, SplineDegree, TabView, Row, Slider, Dynamic, Times, Pi, Power, ImageSize, Small, Slider2D, SetterBar, InputField, FieldSize, Alignment, Left, Spacings, Automatic, LocatorPane, Framed, Graphics, Inset, Cos, Sin, EdgeForm, Directive, AbsoluteThickness, RGBColor, Opacity, Yellow, Rectangle, Dashed, Blue, PlotRange, Plus, LocatorAutoCreate, True, Center, Top, Axes, AspectRatio, Initialization, Null, Condition, String, FileExistsQ, Import, BlankNullSequence, Echo, Inactive, Nothing

Одной из основных функций в работе данной программы является функция DynamicModule для создания интерактивных пространств и объектов. С её помощью происходит "оживление" всей конструкции.

Функция Grid необходима для организации пространства — она позволяет строить таблицы различной формы и размещать в их ячейках контент: тексты, слайдеры, иллюстрации, интерактивные объекты и т. д.

Функции LocatorPane, Slider, Slider2D, InputField служат для того, чтобы сделать интерактивные элементы — поле с выбором точек, слайдеры (одно- и двумерные, соответственно), поле ввода текста (для области определения функции).

Для "рисования" графическими примитивами служит функция Graphics (и если нужно в 3D — то Graphics3D).

И, конечно, самой важной здесь является функция BSplineCurve, которая позволяет представить набор точек в виде готовой кривой B-сплайна.

Программа для оцифровки графиков, чертежей, рисунков

На видео ниже вы можете посмотреть то, как работает программа вживую:

Финальный код программы

Итоговая функция на самом деле не так велика, как могло бы показаться. Хотя это, конечно, прямое следствие больших возможностей Wolfram Language:


Программа для оцифровки графиков, чертежей, рисунков

Код в виде текста
ClearAll[graphicsDigitizing];

graphicsDigitizing[    
    image_Image:
    ImageResize[Image[{{{1,1,1}}},ColorSpace->"RGB"],{600,600}]
]:=
    With[{im=ImageResize[image,600]},
        With[{imdim=ImageDimensions[im]},            
            CreateDialog[
                {
                    ExpressionCell[
                        DynamicModule[                            
                            {                                
                                degree,
                                xmin=0,
                                xmax=1,
                                ymin=0,
                                ymax=1,
                                currentFunction,
                                u,
                                unew,
                                udiap,
                                \[Alpha],
                                \[Beta]1,
                                \[Beta]2
                            },
                            Grid[
                                {                                    
                                    {
                                        DefaultButton[                                            
                                            "Скопировать сплайн в буфер обмена",
                                            DialogReturn[
                                                With[
                                                {                                                    
                                                    var1=
                                                        If[                                                            
                                                            Length[u]
                                                            <
                                                            4,
                                                            None,
                                                            (* else *)                                                            
                                                            unew=
                                                                Drop[                                                                    
                                                                    u,
                                                                    2
                                                                ];
                                                            udiap=
                                                                Transpose[
                                                                    u[                                                                        
                                                                        [                                                                        
                                                                        1
                                                                        ;;
                                                                        2
                                                                        ]
                                                                    ]
                                                                ];                                                            
                                                            Transpose[
                                                                {                                                                    
                                                                    Rescale[                                                                        
                                                                        unew[                                                                            
                                                                            [                                                                            
                                                                            All,
                                                                            1
                                                                            ]
                                                                        ],
                                                                        {                                                                            
                                                                            Min[
                                                                                udiap[                                                                                    
                                                                                    [
                                                                                    1
                                                                                    ]
                                                                                ]
                                                                            ],
                                                                            Max[
                                                                                udiap[                                                                                    
                                                                                    [
                                                                                    1
                                                                                    ]
                                                                                ]
                                                                            ]
                                                                        },
                                                                        {                                                                            
                                                                            xmin,
                                                                            xmax
                                                                        }
                                                                    ],
                                                                    Rescale[                                                                        
                                                                        unew[                                                                            
                                                                            [                                                                            
                                                                            All,
                                                                            2
                                                                            ]
                                                                        ],
                                                                        {                                                                            
                                                                            Min[
                                                                                udiap[                                                                                    
                                                                                    [
                                                                                    2
                                                                                    ]
                                                                                ]
                                                                            ],
                                                                            Max[
                                                                                udiap[                                                                                    
                                                                                    [
                                                                                    2
                                                                                    ]
                                                                                ]
                                                                            ]
                                                                        },
                                                                        {                                                                            
                                                                            ymin,
                                                                            ymax
                                                                        }
                                                                    ]
                                                                }
                                                            ]
                                                            /.
                                                            x_Real:>
                                                                Round[                                                                    
                                                                    x,
                                                                    0.01
                                                                ]
                                                        ],
                                                    var2=degree
                                                },
                                                    CopyToClipboard[
                                                        BSplineCurve[                                                            
                                                            var1,
                                                            SplineDegree->
                                                                var2
                                                        ]
                                                    ]
                                                ]
                                            ]
                                        ]
                                    },
                                    {
                                        TabView[                                            
                                            {                                                
                                                "Оригинал"->
                                                    Grid[                                                        
                                                        {
                                                            {                                                                
                                                                Grid[                                                                    
                                                                    {                                                                        
                                                                        {
                                                                            Row[                                                                                
                                                                                {                                                                                    
                                                                                    "Угол поворота:",
                                                                                    Slider[                                                                                        
                                                                                        Dynamic@
                                                                                            \[Alpha],
                                                                                        {                                                                                                                                                                                                                                                                                    
                                                                                            -
                                                                                            Pi
                                                                                            /
                                                                                            6,                                                                                            
                                                                                            Pi
                                                                                            /
                                                                                            6
                                                                                        },
                                                                                        ImageSize->
                                                                                            Small
                                                                                    ]
                                                                                },
                                                                                " "
                                                                            ]
                                                                        },
                                                                        {
                                                                            Row[                                                                                
                                                                                {                                                                                    
                                                                                    "Отступы:",
                                                                                    Slider2D[                                                                                        
                                                                                        Dynamic[
                                                                                            \[Beta]1
                                                                                        ],
                                                                                        {                                                                                                                                                                                        
                                                                                            0.2
                                                                                            Max[
                                                                                                imdim
                                                                                            ]
                                                                                            {                                                                                                                                                                                                
                                                                                                -
                                                                                                1,                                                                                                
                                                                                                -
                                                                                                1
                                                                                            },                                                                                            
                                                                                            0.2
                                                                                            Max[
                                                                                                imdim
                                                                                            ]
                                                                                            {                                                                                                
                                                                                                1,
                                                                                                1
                                                                                            }
                                                                                        }
                                                                                    ],
                                                                                    Slider2D[                                                                                        
                                                                                        Dynamic[
                                                                                            \[Beta]2
                                                                                        ],
                                                                                        {                                                                                                                                                                                        
                                                                                            0.2
                                                                                            Max[
                                                                                                imdim
                                                                                            ]
                                                                                            {                                                                                                                                                                                                
                                                                                                -
                                                                                                1,                                                                                                
                                                                                                -
                                                                                                1
                                                                                            },                                                                                            
                                                                                            0.2
                                                                                            Max[
                                                                                                imdim
                                                                                            ]
                                                                                            {                                                                                                
                                                                                                1,
                                                                                                1
                                                                                            }
                                                                                        }
                                                                                    ]
                                                                                },
                                                                                " "
                                                                            ]
                                                                        },
                                                                        {
                                                                            Row[                                                                                
                                                                                {                                                                                    
                                                                                    "Степень сплайна:",
                                                                                    SetterBar[                                                                                        
                                                                                        Dynamic@
                                                                                            degree,
                                                                                        {                                                                                            
                                                                                            0,
                                                                                            1,
                                                                                            2,
                                                                                            3,
                                                                                            4
                                                                                        }
                                                                                    ]
                                                                                },
                                                                                " "
                                                                            ]
                                                                        },
                                                                        {
                                                                            Grid[
                                                                                {                                                                                    
                                                                                    {                                                                                        
                                                                                        "\!\(\*SubscriptBox[\(x\), \(min\)]\) =",
                                                                                        InputField[                                                                                            
                                                                                            Dynamic[
                                                                                                xmin
                                                                                            ],
                                                                                            FieldSize->
                                                                                                {                                                                                                    
                                                                                                    3,
                                                                                                    1
                                                                                                }
                                                                                        ],
                                                                                        "\!\(\*SubscriptBox[\(x\), \(max\)]\) =",
                                                                                        InputField[                                                                                            
                                                                                            Dynamic[
                                                                                                xmax
                                                                                            ],
                                                                                            FieldSize->
                                                                                                {                                                                                                    
                                                                                                    3,
                                                                                                    1
                                                                                                }
                                                                                        ]
                                                                                    },
                                                                                    {                                                                                        
                                                                                        "\!\(\*SubscriptBox[\(y\), \(min\)]\) =",
                                                                                        InputField[                                                                                            
                                                                                            Dynamic[
                                                                                                ymin
                                                                                            ],
                                                                                            FieldSize->
                                                                                                {                                                                                                    
                                                                                                    3,
                                                                                                    1
                                                                                                }
                                                                                        ],
                                                                                        "\!\(\*SubscriptBox[\(y\), \(max\)]\) =",
                                                                                        InputField[                                                                                            
                                                                                            Dynamic[
                                                                                                ymax
                                                                                            ],
                                                                                            FieldSize->
                                                                                                {                                                                                                    
                                                                                                    3,
                                                                                                    1
                                                                                                }
                                                                                        ]
                                                                                    }
                                                                                }
                                                                            ]
                                                                        }
                                                                    },
                                                                    Alignment->
                                                                        Left,
                                                                    Spacings->
                                                                        {                                                                            
                                                                            Automatic,
                                                                            1
                                                                        }
                                                                ],
                                                                LocatorPane[                                                                    
                                                                    Dynamic@
                                                                        u,
                                                                    Framed@
                                                                        Dynamic@
                                                                            Graphics[                                                                                
                                                                                {                                                                                    
                                                                                    Inset[                                                                                        
                                                                                        im,
                                                                                        {                                                                                            
                                                                                            0,
                                                                                            0
                                                                                        },
                                                                                        {                                                                                            
                                                                                            0,
                                                                                            0
                                                                                        },
                                                                                        imdim,
                                                                                        {                                                                                            
                                                                                            Cos[
                                                                                                \[Alpha]
                                                                                            ],
                                                                                            Sin[
                                                                                                \[Alpha]
                                                                                            ]
                                                                                        }
                                                                                    ],
                                                                                    {                                                                                        
                                                                                        EdgeForm[
                                                                                            Directive[                                                                                                
                                                                                                AbsoluteThickness[
                                                                                                    3
                                                                                                ],
                                                                                                RGBColor[                                                                                                    
                                                                                                    {                                                                                                        
                                                                                                        214,
                                                                                                        0,
                                                                                                        0
                                                                                                    }
                                                                                                    /
                                                                                                    255
                                                                                                ]
                                                                                            ]
                                                                                        ],
                                                                                        Opacity[                                                                                            
                                                                                            0.2,
                                                                                            Yellow
                                                                                        ],
                                                                                        Rectangle[                                                                                            
                                                                                            u[                                                                                                
                                                                                                [
                                                                                                1
                                                                                                ]
                                                                                            ],
                                                                                            u[                                                                                                
                                                                                                [
                                                                                                2
                                                                                                ]
                                                                                            ]
                                                                                        ]
                                                                                    },
                                                                                    {                                                                                        
                                                                                        Dashed,
                                                                                        Blue,
                                                                                        AbsoluteThickness[
                                                                                            4
                                                                                        ],
                                                                                        If[                                                                                            
                                                                                            Length[
                                                                                                u
                                                                                            ]
                                                                                            <
                                                                                            4,
                                                                                            BSplineCurve[                                                                                                
                                                                                                u[                                                                                                    
                                                                                                    [                                                                                                    
                                                                                                    1
                                                                                                    ;;
                                                                                                    2
                                                                                                    ]
                                                                                                ],
                                                                                                SplineDegree->
                                                                                                    2
                                                                                            ],
                                                                                            (* else *)
                                                                                            BSplineCurve[                                                                                                
                                                                                                Drop[                                                                                                    
                                                                                                    u,
                                                                                                    2
                                                                                                ],
                                                                                                SplineDegree->
                                                                                                    degree
                                                                                            ]
                                                                                        ]
                                                                                    }
                                                                                },
                                                                                PlotRange->
                                                                                    Transpose[
                                                                                        {                                                                                            
                                                                                            \[Beta]1,                                                                                            
                                                                                            imdim
                                                                                            +
                                                                                            \[Beta]2
                                                                                        }
                                                                                    ],
                                                                                ImageSize->
                                                                                    600
                                                                            ],
                                                                    LocatorAutoCreate->
                                                                        True
                                                                ]
                                                            }
                                                        },
                                                        Alignment->
                                                            {                                                                
                                                                Center,
                                                                Top
                                                            }
                                                    ],
                                                "Результат"->
                                                    Dynamic@
                                                        Graphics[                                                            
                                                            {                                                                
                                                                Blue,
                                                                AbsoluteThickness[
                                                                    2
                                                                ],
                                                                If[                                                                    
                                                                    Length[
                                                                        u
                                                                    ]
                                                                    <
                                                                    4,
                                                                    BSplineCurve[                                                                        
                                                                        u[                                                                            
                                                                            [                                                                            
                                                                            1
                                                                            ;;
                                                                            2
                                                                            ]
                                                                        ],
                                                                        SplineDegree->
                                                                            2
                                                                    ],
                                                                    (* else *)
                                                                    BSplineCurve[                                                                                                                                                
                                                                        unew=
                                                                            Drop[                                                                                
                                                                                u,
                                                                                2
                                                                            ];
                                                                        udiap=
                                                                            Transpose[
                                                                                u[                                                                                    
                                                                                    [                                                                                    
                                                                                    1
                                                                                    ;;
                                                                                    2
                                                                                    ]
                                                                                ]
                                                                            ];
                                                                        Transpose[
                                                                            {                                                                                
                                                                                Rescale[                                                                                    
                                                                                    unew[                                                                                        
                                                                                        [                                                                                        
                                                                                        All,
                                                                                        1
                                                                                        ]
                                                                                    ],
                                                                                    {                                                                                        
                                                                                        Min[
                                                                                            udiap[                                                                                                
                                                                                                [
                                                                                                1
                                                                                                ]
                                                                                            ]
                                                                                        ],
                                                                                        Max[
                                                                                            udiap[                                                                                                
                                                                                                [
                                                                                                1
                                                                                                ]
                                                                                            ]
                                                                                        ]
                                                                                    },
                                                                                    {                                                                                        
                                                                                        xmin,
                                                                                        xmax
                                                                                    }
                                                                                ],
                                                                                Rescale[                                                                                    
                                                                                    unew[                                                                                        
                                                                                        [                                                                                        
                                                                                        All,
                                                                                        2
                                                                                        ]
                                                                                    ],
                                                                                    {                                                                                        
                                                                                        Min[
                                                                                            udiap[                                                                                                
                                                                                                [
                                                                                                2
                                                                                                ]
                                                                                            ]
                                                                                        ],
                                                                                        Max[
                                                                                            udiap[                                                                                                
                                                                                                [
                                                                                                2
                                                                                                ]
                                                                                            ]
                                                                                        ]
                                                                                    },
                                                                                    {                                                                                        
                                                                                        ymin,
                                                                                        ymax
                                                                                    }
                                                                                ]
                                                                            }
                                                                        ],
                                                                        SplineDegree->
                                                                            degree
                                                                    ]
                                                                ]
                                                            },
                                                            PlotRange->
                                                                {                                                                    
                                                                    {                                                                        
                                                                        xmin,
                                                                        xmax
                                                                    },
                                                                    {                                                                        
                                                                        ymin,
                                                                        ymax
                                                                    }
                                                                },
                                                            ImageSize->
                                                                600,
                                                            Axes->True,
                                                            AspectRatio->                                                                
                                                                imdim[                                                                    
                                                                    [
                                                                    2
                                                                    ]
                                                                ]
                                                                /
                                                                imdim[                                                                    
                                                                    [
                                                                    1
                                                                    ]
                                                                ]
                                                        ]
                                            },
                                            Alignment->Center
                                        ]
                                    }
                                }
                            ],
                            Initialization:>
                                (                                    
                                    u={{0,0},imdim};
                                    \[Alpha]=0;
                                    degree=3;
                                    \[Beta]1=0.1Max[imdim]{-1,-1};
                                    \[Beta]2=0.1Max[imdim]{1,1}
                                )
                        ]
                    ]
                }
            ];
        ]
    ];

graphicsDigitizing[image_String/;FileExistsQ[image]]:=
    graphicsDigitizing[Import[image]];

graphicsDigitizing[x___]:=
    (        
        Echo[            
            Inactive[graphicsDigitizing][x],
            "Не подходящие параметры: "
        ];
        Nothing
    )

Преимущества работы с оцифрованными функциями на примерах

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

Например, пусть дан график:

Программа для оцифровки графиков, чертежей, рисунков

Давайте оцифруем его (см. видео выше) и произведем вычисления.

Для начала только заменим головную часть полученного в ходе работы программы выражения с BSplineCurve на BSplineFunction, которая строит аналитическое выражение с которым можно уже производить вычисления:

Программа для оцифровки графиков, чертежей, рисунков

Единственный недостаток — это то, что такая функция нормирована на 1, т. е. функция f(t) при изменении t от 0 до 1 пробежит все свои значения, которыми являются точки B-сплайна:

Программа для оцифровки графиков, чертежей, рисунков

Однако, с этим легко бороться. Достаточно построить интерполяционный полином:

Программа для оцифровки графиков, чертежей, рисунков

После этого уже можно делать, что угодно.

Построить график, скажем, от 1 до 9:

Программа для оцифровки графиков, чертежей, рисунков

Проинтегрировать функцию по всей области задания:

Программа для оцифровки графиков, чертежей, рисунков

Построить график производной:

Программа для оцифровки графиков, чертежей, рисунков

Найти длину кривой:

Программа для оцифровки графиков, чертежей, рисунков

Или же аналитическое представление кривой (в параметрическом виде):

Программа для оцифровки графиков, чертежей, рисунков

Код в виде текста
pts=
    Rationalize[        
        {            
            {0.01`,10.92`},
            {0.19`,16.36`},
            {0.34`,20.76`},
            {0.55`,25.17`},
            {0.96`,29.57`},
            {1.9100000000000001`,34.49`},
            {2.74`,38.63`},
            {3.38`,42.09`},
            {3.97`,44.03`},
            {4.47`,49.77`},
            {4.88`,56.5`},
            {5.29`,63.24`},
            {5.65`,69.19`},
            {6.0600000000000005`,74.63`},
            {6.53`,78.52`},
            {7.0200000000000005`,83.96000000000001`},
            {7.46`,86.55`},
            {8.02`,89.4`},
            {8.26`,86.55`},
            {8.67`,82.4`},
            {9.21`,80.85000000000001`},
            {9.57`,79.81`},
            {9.93`,79.81`}
        },
        1/100
    ];

ptsL=Length[pts];

splineDegree=3;

knots=    
    ConstantArray[0,splineDegree]
    ~
    Join
    ~
    Subdivide[ptsL-splineDegree]
    ~
    Join
    ~
    ConstantArray[1,splineDegree];

FullSimplify@
    Simplify[
        Sum[                        
            pts[[i+1]]
            PiecewiseExpand[BSplineBasis[{splineDegree,knots},i,t]],
            {i,0,ptsL-1}
        ]
    ]

А можно, конечно, и просто облагородить изначальный график:

Программа для оцифровки графиков, чертежей, рисунков

Оценить статью
Блог о Wolfram Mathematica

Оставить комментарий

avatar
  Подписаться  
Уведомление о