Масштабирование изображения не выбирает правильную область - PullRequest
0 голосов
/ 12 января 2020

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

Я установил виджет изображения на 600x600. Чтобы сохранить соотношение сторон, я затем масштабирую изображение и рисую его в виджет. Это работает очень хорошо.

Для функции масштабирования пользователь должен щелкнуть мышью в любом месте изображения, и он должен обрезать пиксели размером 150x150 вокруг места щелчка курсора. Чтобы быть точным, щелчок курсора должен отмечать середину прямоугольника, который я вырезал. Так что, если я нажму на x = 300 y = 300, площадь должна быть x = 225 y = 225 width = 150 height = 150.

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

Ошибка проста. Вырезанная область - не совсем та область, которую я хотел бы вырезать. Иногда это далеко слева. Иногда в крайнее право. Somtes к высокому иногда к низкому ... И я не вижу, в чем проблема.

Я написал прототип barebone с только необходимой функциональностью. После того, как вы введете путь к изображению в формате JPEG, вы сможете запустить его.

# -*- coding: utf-8 -*-
"""
Created on Sun Jan 12 12:22:25 2020

@author: Paddy
"""

import wx


class ImageTest(wx.App):
    def __init__(self, redirect=False, filename=None):
        wx.App.__init__(self, redirect, filename)

        self.frame = wx.Frame(None, title='Radsteuer Eintreiber')   

        self.panelleft = wx.Panel(self.frame)
        self.picturepresent=False
        self.index=0
        self.PhotoMaxSize = 600
        self.zoomed=False
        #Change path here
        self.imagepath='F:\Geolocation\Test\IMG_20191113_174257.jpg'
        self.createUI()
        self.frame.Centre()
        self.frame.Show()
        self.frame.Raise()
        self.onView()
    #Creates UI Elements on Initiation    
    def createUI(self):
        #instructions = 'Bild'
        img = wx.Image(self.PhotoMaxSize,self.PhotoMaxSize,clear=True)
        self.imageCtrl = wx.StaticBitmap(self.panelleft, wx.ID_ANY, 
                                         wx.Bitmap(img),size=(self.PhotoMaxSize,self.PhotoMaxSize))
        self.mainSizer = wx.BoxSizer(wx.VERTICAL)        

        self.imageCtrl.Bind(wx.EVT_LEFT_UP, self.onImageClick)     


        self.mainSizer.Add(self.imageCtrl, 0, wx.ALL|wx.ALIGN_CENTER, 5)

        self.panelleft.SetSizer(self.mainSizer)
        self.mainSizer.Fit(self.frame)

        self.panelleft.Layout()




    def onImageClick(self,event):
        if self.zoomed:
            self.onView()
            self.zoomed=False
        else :
            #Determin position of mouse
            ctrl_pos = event.GetPosition()
            print(ctrl_pos)
            picturecutof=self.PhotoMaxSize/4
            if ctrl_pos[0]-((self.PhotoMaxSize-self.NewW)/2)>0:
                xpos=ctrl_pos[0]-((self.PhotoMaxSize-self.NewW)/2)
            else:
                xpos=0                
            if ctrl_pos[0]+picturecutof>self.NewW:
                xpos=self.NewW-picturecutof


            if ctrl_pos[1]-((self.PhotoMaxSize-self.NewW)/2)>0:
                ypos=ctrl_pos[1]-((self.PhotoMaxSize-self.NewW)/2)
            else:
                ypos=0                
            if ctrl_pos[1]+picturecutof>self.NewH:
                ypos=self.NewH-picturecutof


            xpos=xpos*self.W/self.NewW    
            ypos=ypos*self.H/self.NewH
            picturecutofx=picturecutof*self.W/self.NewW
            picturecutofy=picturecutof*self.H/self.NewH

            rectangle=wx.Rect(xpos,ypos,picturecutofx,picturecutofy)
            self.img = wx.Image(self.imagepath, wx.BITMAP_TYPE_ANY)
            self.img=self.img.GetSubImage(rectangle)

            self.img=self.img.Scale(600,600,wx.IMAGE_QUALITY_BICUBIC)
            self.imageCtrl.SetBitmap(wx.Bitmap(self.img))
            self.imageCtrl.Fit()
            self.panelleft.Refresh()
            self.zoomed=True

    def onView(self,event=None):


        self.img = wx.Image(self.imagepath, wx.BITMAP_TYPE_ANY)
        # scale the image, preserving the aspect ratio
        self.W = self.img.GetWidth()
        self.H = self.img.GetHeight()

        if self.W > self.H:
            self.NewW = self.PhotoMaxSize
            self.NewH = self.PhotoMaxSize * self.H / self.W
        else:
            self.NewH = self.PhotoMaxSize 
            self.NewW = self.PhotoMaxSize * self.W / self.H

        self.img = self.img.Scale(self.NewW,self.NewH,wx.IMAGE_QUALITY_BICUBIC)        
        self.imageCtrl.SetBitmap(wx.Bitmap(self.img))
        self.imageCtrl.Fit()
        self.panelleft.Refresh()

if __name__ == '__main__':

    app = ImageTest()
    app.MainLoop()   

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

Функциональность этого протопайя проста: замените путь на изображение вашего чойче в формате jpge. Запустите программу. Нажмите на изображение, и оно должно увеличиться. Кликните вокруг своего изображения, и вы увидите, что масштабирование неверно.

Вот и все. Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 19 января 2020

Итак, я нашел ответ. Но я изменил что-то в логи c также. Теперь картинка будет центрирована в том месте, где пользователь щелкнул. Это гораздо более интуитивно понятно. Я только отправляю функцию onImageClick. Если вы хотите использовать все это, не стесняйтесь заменить его в исходном коде из вопроса.

def onImageClick(self,event):
    if self.zoomed:
        self.onView()
        self.zoomed=False
    else :
        #Determin position of mouse
        ctrl_pos = event.GetPosition()

        #Set magnification.
        scalingfactor=4       

        #Set Picture size for rectangle            
        picturecutof=self.PhotoMaxSize/scalingfactor

        ##Find coordinates by adjusting for picture position
        xpos=ctrl_pos[0]-((self.PhotoMaxSize-self.NewW)/2) 
        ypos=ctrl_pos[1]-((self.PhotoMaxSize-self.NewH)/2)

        #if position is out of range adjust
        if xpos>self.NewW:
            xpos=self.NewW
        if xpos<0:
            xpos=0

        if ypos>self.NewH:
            ypos=self.NewH
        if ypos<0:
            ypos=0


        #scale rectangle area to size of the unscaled image
        picturecutofx=picturecutof*self.W/self.NewW            
        picturecutofy=picturecutof*self.H/self.NewH



        #scale coordinates to unscaled image
        xpos=xpos*self.W/self.NewW
        ypos=ypos*self.H/self.NewH

        #centeres image onto the coordinates where they were clicked
        xpos=xpos-((ctrl_pos[0]*self.W/self.NewW)/scalingfactor)
        ypos=ypos-((ctrl_pos[1]*self.H/self.NewH)/scalingfactor)


        #if position is out of range adjust
        if xpos>self.W-picturecutofx:
            xpos=self.W-picturecutofx-5
        if xpos<0:
            xpos=0

        if ypos>self.H-picturecutofy:
            ypos=self.H-picturecutofy-5
        if ypos<0:
            ypos=0

        #create rectangle to cut from original image
        rectangle=wx.Rect(xpos,ypos,picturecutofx,picturecutofy)
        #load original image again
        self.img = wx.Image(self.imagepath, wx.BITMAP_TYPE_ANY)
        #get subimage 
        self.img=self.img.GetSubImage(rectangle)

        #scale subimage to picture area
        self.img=self.img.Scale(self.PhotoMaxSize,self.PhotoMaxSize,wx.IMAGE_QUALITY_BICUBIC)
        self.imageCtrl.SetBitmap(wx.Bitmap(self.img))
        self.imageCtrl.Fit()
        self.panelleft.Refresh()
        self.zoomed=True

    event.Skip()
...