Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
以說,每一個“使用計算機的人”都需要在某個時間點調整圖像的大小。MacOS的預覽版可以做到,WindowsPowerToys也可以。
本文使用Python來調整圖像大小,幸運的是,圖像處理和命令行工具是Python的兩個特長。
本文旨在向你展示三件事:
我們要構建的命令行程序可以一次調整一個或多個圖像文件的大小。
在這個例子中,我們將創建我們自己的圖像,而不是找到一個真正的圖像來操縱。
為什么?事實上,創造圖像是一個很好的方式來說明一個圖像實際上是什么。這個調整大小的程序在Instagram上也同樣適用。
那么,什么是圖像?在Python數據術語中,圖像是int元組的列表。
image=list[list[tuple[*int, float]]]
NumPy的定義是一個二維形狀數組 (h, w, 4),其中h表示高的像素數(上下),w表示寬的像素數(從左到右)。
換句話說,圖像是像素列表(行)的列表(整個圖像)。每個像素由3個整數和1個可選浮點數組成:紅色通道、綠色通道、藍色通道、alpha(浮點可選)。紅色、綠色、藍色通道(RGB)的值從0到255。
從現在開始,我們將討論沒有alpha通道的彩色圖像,以保持簡單。Alpha是像素的透明度。圖像也只能有一個值從0到255的通道。這就是灰度圖像,也就是黑白圖像。在這里我們使用彩色圖像!
import matplotlib as plt
pixel: tuple=(200, 100, 150)
plt.imshow([[list(pixel)]])
Python完全能夠創建圖像。要顯示它,我將使用matplotlib庫,你可以使用它安裝:
pip install matplotlib
創建像素:
from dataclasses import dataclass
@dataclass
class Pixel:
red: int
green: int
blue: int
# alpha: float=1
pixel=Pixel(255,0,0)
pixel
# returns:
# Pixel(red=255, green=0, blue=0, alpha=1)
創建圖像:
from __future__ import annotations
from dataclasses import dataclass, astuple
from itertools import cycle
from typing import List
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
@dataclass
class Pixel:
red: int
green: int
blue: int
# alpha: float=1
pixel=Pixel(255,0,0)
pixel
marigold: Pixel=Pixel(234,162,33)
red: Pixel=Pixel(255,0,0)
Image=List[List[Pixel]]
def create_image(*colors: Pixel, blocksize: int=10, squaresize: int=9) -> Image:
""" 用可配置的像素塊制作一個正方形圖像(寬度和高度相同).
Args:
colors (Pixel): 可迭代的顏色呈現順序的參數。
blocksize (int, optional): [description]. 默認10.
squaresize (int, optional): [description]. 默認9.
Returns:
Image: 一幅漂亮的正方形圖片!
"""
img: list=[]
colors=cycle(colors)
for row in range(squaresize):
row: list=[]
for col in range(squaresize):
color=next(colors) # 設置顏色
for _ in range(blocksize):
values: list[int]=list(astuple(color))
row.append(values)
[img.append(row) for _ in range(squaresize)] # 創建行高
return img
if __name__=='__main__':
image=create_image(marigold, red)
plt.imshow(image)
這就是渲染的圖像。在背后,數據是這樣的:
[[[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[234, 162, 33],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[255, 0, 0],
[234, 162, 33],
...
現在我們有了一個圖像,讓我們調整它的大小!
在Python中編寫調整圖像大小的算法實際上有很多的工作量。
在圖像處理算法中有很多內容,有些人為此貢獻了十分多的工作。例如重采樣——在縮小后的圖像中使用一個像素來代表周圍的高分辨率像素。圖像處理是一個巨大的話題。如果你想親眼看看,看看Pillow的Image.py,它在路徑path/to/site-packages/PIL中。
這中間還有一些優化,比如抗鋸齒和減少間隙…這里的內容非常多。我們是站在巨人的肩膀上,可以用一行代碼來解決我們的問題。
如果你有興趣了解更多有關處理圖像時幕后發生的事情,我鼓勵你更多地查看“機器視覺”主題!這絕對是一個蓬勃發展的領域。
做得足夠好,就會有很多公司愿意為你的計算機視覺專業知識付出最高的代價。自動駕駛,IOT,監視,你命名它;所有基本上依賴于處理圖片(通常在Python或C++)。
一個很好的起點是查看scikit image。
OpenCV可以用來作圖像處理。他使用C++編寫并移植到了Python
import cv2
def resize(fp: str, scale: Union[float, int]) -> np.ndarray:
""" 調整圖像大小,保持其比例
Args:
fp (str): 圖像文件的路徑參數
scale (Union[float, int]): 百分比作為參數。如:53
Returns:
image (np.ndarray): 按比例縮小的圖片
"""
_scale=lambda dim, s: int(dim * s / 100)
im: np.ndarray=cv2.imread(fp)
width, height, channels=im.shape
new_width: int=_scale(width, scale)
new_height: int=_scale(height, scale)
new_dim: tuple=(new_width, new_height)
return cv2.resize(src=im, dsize=new_dim, interpolation=cv2.INTER_LINEAR)
interpolation參數的選項是cv2包中提供的flags之一:
INTER_NEAREST – 近鄰插值
INTER_LINEAR – 雙線性插值(默認使用)
INTER_AREA – 利用像素區域關系重新采樣。它可能是圖像抽取的首選方法。但是當圖像被縮放時,它類似于INTER_NEAREST方法。
INTER_CUBIC – 一個大于4×4像素鄰域的雙三次插值
INTER_LANCZOS4 – 一個大于8×8像素鄰域的Lanczos插值
返回后:
resized=resize("checkers.jpg", 50)
print(resized.shape)
plt.imshow(resized) # 也可以使用 cv2.imshow("name", image)
它做了我們所期望的。圖像從900像素高,900像素寬,到450×450(仍然有三個顏色通道)。因為Jupyter Lab的matplotlib著色,上面的屏幕截圖看起來不太好。
pillow庫在Image類上有一個調整大小的方法。它的參數是:
size: (width, height)
resample: 默認為BICUBIC. 重采樣算法需要的參數。
box: 默認為None。為一個4元組,定義了在參數(0,0,寬度,高度)內工作的圖像矩形。
reducing_gap: 默認為None。重新采樣優化算法,使輸出看起來更好。
以下是函數:
from PIL import Image
def resize(fp: str, scale: Union[float, int]) -> np.ndarray:
""" 調整圖像大小,保持其比例
Args:
fp (str): 圖像文件的路徑參數
scale (Union[float, int]): 百分比作為參數。如:53
Returns:
image (np.ndarray): 按比例縮小的圖片
"""
_scale=lambda dim, s: int(dim * s / 100)
im=Image.open(fp)
width, height=im.size
new_width: int=_scale(width, scale)
new_height: int=_scale(height, scale)
new_dim: tuple=(new_width, new_height)
return im.resize(new_dim)
使用Pillow 的函數與OpenCV非常相似。唯一的區別是PIL.Image.Image類具有用于訪問圖像(寬度、高度)的屬性大小。
結果是:
resized=resize("checkers.jpg", 30.5)
print(resized.size)
resized.show("resized image", resized)
請注意show方法如何打開操作系統的默認程序以查看圖像的文件類型。
現在我們有了一個調整圖像大小的函數,現在是時候讓它有一個運行調整大小的用戶界面了。
調整一個圖像的大小是可以的。但我們希望能夠批量處理圖像。
我們將要構建的接口將是最簡單的接口:命令行實用程序。
Pallets項目是Flask背后的天才社區,是一個Jinja模板引擎:Click(https://click.palletsprojects.com/en/7.x/。)
pip install click
Click是一個用于制作命令行程序的庫。這比使用普通的argparse或在if __name__=='__main__':中啟動一些if-then邏輯要好得多。所以,我們將使用Click來裝飾我們的圖像調整器。
下面是從命令行調整圖像大小的完整腳本!
""" resize.py
"""
from __future__ import annotations
import os
import glob
from pathlib import Path
import sys
import click
from PIL import Image
"""
文檔:
https://pillow.readthedocs.io/en/5.1.x/handbook/image-file-formats.html
"""
SUPPORTED_FILE_TYPES: list[str]=[".jpg", ".png"]
def name_file(fp: Path, suffix) -> str:
return f"{fp.stem}{suffix}{fp.suffix}"
def resize(fp: str, scale: Union[float, int]) -> Image:
""" 調整圖像大小,保持其比例
Args:
fp (str): 圖像文件的路徑參數
scale (Union[float, int]): 百分比作為參數。如:53
Returns:
image (np.ndarray): 按比例縮小的圖片
"""
_scale=lambda dim, s: int(dim * s / 100)
im: PIL.Image.Image=Image.open(fp)
width, height=im.size
new_width: int=_scale(width, scale)
new_height: int=_scale(height, scale)
new_dim: tuple=(new_width, new_height)
return im.resize(new_dim)
@click.command()
@click.option("-p", "--pattern")
@click.option("-s", "--scale", default=50, help="Percent as whole number to scale. eg. 40")
@click.option("-q", "--quiet", default=False, is_flag=True, help="Suppresses stdout.")
def main(pattern: str, scale: int, quiet: bool):
for image in (images :=Path().glob(pattern)):
if image.suffix not in SUPPORTED_FILE_TYPES:
continue
im=resize(image, scale)
nw, nh=im.size
suffix: str=f"_{scale}_{nw}x{nh}"
resize_name: str=name_file(image, suffix)
_dir: Path=image.absolute().parent
im.save(_dir / resize_name)
if not quiet:
print(
f"resized image saved to {resize_name}.")
if images==[]:
print(f"No images found at search pattern '{pattern}'.")
return
if __name__=='__main__':
main()
命令行程序從入口點函數main運行。參數通過傳遞給click.option選項:
從命令行運行程序:
python resize.py -s 35 -p "./*jpg"
結果:
$ py resize.py -p "checkers.jpg" -s 90
resized image saved to checkers_90_810x810.jpg.
正在檢查文件夾:
$ ls -lh checkers*
-rw-r--r-- 1 nicho 197609 362K Aug 15 13:13 checkers.jpg
-rw-r--r-- 1 nicho 197609 231K Aug 15 23:56 checkers_90_810x810.jpg
不錯!所以程序縮小了圖像,給了它一個描述性的標簽,我們可以看到文件大小從362KB到231KB!
為了查看程序同時處理多個文件,我們將再次運行它:
$ py resize.py --pattern="checkers*" --scale=20
resized image saved to checkers_20_180x180.jpg.
resized image saved to checkers_90_810x810_20_162x162.jpg.
文件系統輸出:
$ ll -h checkers*
-rw-r--r-- 1 nicho 197609 362K Aug 15 13:13 checkers.jpg
-rw-r--r-- 1 nicho 197609 1.8K Aug 16 00:23 checkers_20_180x180.jpg
-rw-r--r-- 1 nicho 197609 231K Aug 15 23:56 checkers_90_810x810.jpg
-rw-r--r-- 1 nicho 197609 1.8K Aug 16 00:23 checkers_90_810x810_20_162x162.jpg
只要匹配到了模式,遞歸可以處理任意數量的圖像。
Click 是一個神奇的工具。它可以包裝一個函數并在一個模塊中以“正常的方式”從一個if __name__=='__main__'語句運行。(實際上,它甚至不需要這樣做;你只需定義和裝飾要運行的函數即可),但它真正的亮點在于將腳本作為包安裝。
這是通過Python附帶的setuptools庫完成的。
這是我的setup.py.
from setuptools import setup
setup(
name='resize',
version='0.0.1',
py_modules=['resize'],
install_requires=[
'click',
'pillow',
],
entry_points='''
[console_scripts]
resize=resize:main
'''
)
使用以下命令生成可執行文件/包裝包:
pip install -e .
現在,你可以在不使用python命令的情況下調用腳本。另外,如果你將新的可執行文件添加到路徑中的文件夾中,你可以從計算機上的任何位置調用此程序,如resize -p *jpg -s 75
本教程進行了大量的研究:
請記住,編寫代碼可能需要數小時或數天。但它只需幾毫秒就可以運行。你制作的程序不必很大。任何一件能節省你的時間或讓你產生更多產出的東西,都有可能為你的余生服務!
作放大鏡,首先必須要掌握常見的六大尺寸值。如果這六個值不太熟悉的話,可能有點吃力,不過下圖已經分析的很清楚了,應該能看懂。需要注意的一點是,除了鼠標位置是按照窗口來進行定位的,如圖綠色畫線,其他四項尺寸值是按照父元素——子元素關系來計算尺寸,如body和div1,div1和div2 。
offsetLeft和style.left主要有三點不同:
現在來分析:當放大鏡(鼠標)在小圖片上移動 x 距離時,大圖片移動的距離Y是多少呢?
其實根據 等比 關系,有圖中的關系:
下圖中關系式,其實就是由核心公式轉化而來:X/?=B/D=A/C.
(為了方便,只討論單方向和橫軸方向距離)
X:放大鏡向左移動的距離;
?:大圖片向右(反方向)移動的距離;
A:放大鏡的寬;
B:小容器的寬,為了兼容,實際為mark的寬,不過與小容器寬相等的;
C:大容器的寬;
D:大圖片的寬;
圖中數字代表距離,則x的值應該如下計算:
上面就是放大鏡核心原理。明白了原理后,對于放大鏡的移動范圍,瀏覽器的兼容性等細節再進行優化可以咯。
代碼還是要貼上來的:
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>放大鏡</title> <style> * { margin: 0; padding: 0 } // 最外層,包裹所有元素 #demo { display: block; width: 400px; height: 255px; margin: 50px; position: relative; border: 1px solid #ccc; } // 小容器 #small-box { position: relative; z-index: 1; } // 放大鏡 #float-box { display: none; width: 160px; height: 120px; position: absolute; background: #ffffcc; border: 1px solid #ccc; filter: alpha(opacity=50); opacity: 0.5; } // 為了兼容IE,把添加在小圖片的特性全部移到mark #mark { position: absolute; display: block; width: 400px; height: 255px; background-color: #fff; filter: alpha(opacity=0); opacity: 0; z-index: 10; } // 大容器 #big-box { display: none; position: absolute; top: 0; left: 460px; width: 400px; height: 300px; overflow: hidden; border: 1px solid #ccc; z-index: 1; ; } // 大圖片 #big-box img { position: absolute; z-index: 5 } </style> <script> //頁面加載完畢后執行 window.onload=function() { var objDemo=document.getElementById("demo"); var objSmallBox=document.getElementById("small-box"); var objMark=document.getElementById("mark"); var objFloatBox=document.getElementById("float-box"); var objBigBox=document.getElementById("big-box"); var objBigBoxImage=objBigBox.getElementsByTagName("img")[0]; // 鼠標移入時觸發的事件 objMark.onmouseover=function() { objFloatBox.style.display="block" objBigBox.style.display="block" } // 鼠標離開時觸發的事件 objMark.onmouseout=function() { objFloatBox.style.display="none" objBigBox.style.display="none" } // 鼠標在小圖片上移動時觸發的事件 objMark.onmousemove=function(ev) { // 兼容瀏覽器 var _event=ev || window.event; // 鼠標移動的 變化距離 var left=_event.clientX - objDemo.offsetLeft - objSmallBox.offsetLeft - objFloatBox.offsetWidth / 2; var top=_event.clientY - objDemo.offsetTop - objSmallBox.offsetTop - objFloatBox.offsetHeight / 2; // 把放大鏡限制在小容器內 if (left < 0) { left=0; } else if (left > (objMark.offsetWidth - objFloatBox.offsetWidth)) { left=objMark.offsetWidth - objFloatBox.offsetWidth; } if (top < 0) { top=0; } else if (top > (objMark.offsetHeight - objFloatBox.offsetHeight)) { top=objMark.offsetHeight - objFloatBox.offsetHeight; } //放大鏡跟隨鼠標發生移動后的當前位置 objFloatBox.style.left=left + "px"; objFloatBox.style.top=top + "px"; //發生移動后,產生的 等比例 關系。 var percentX=left / (objMark.offsetWidth - objFloatBox.offsetWidth); var percentY=top / (objMark.offsetHeight - objFloatBox.offsetHeight); //利用等比例關系計算 大圖片 反向 移動的距離 objBigBoxImage.style.left=-percentX * (objBigBoxImage.offsetWidth - objBigBox.offsetWidth) + "px"; objBigBoxImage.style.top=-percentY * (objBigBoxImage.offsetHeight - objBigBox.offsetHeight) + "px"; } } </script> </head> <body> <div id="demo"> <div id="small-box"> <div id="mark"></div> <div id="float-box"></div> <img src="macbook-small.jpg" /> // 這張是小圖片。 </div> <div id="big-box"> <img src="macbook-big.jpg" /> // 這張是大圖片。 </div> </div> </body> </html>
這張是小圖片,可以下載后置于源碼中使用。
這張是大圖片,可以下載后置于源碼中使用。
了點時間寫的,蠻長時間了。個人很喜歡,一段很簡單的代碼,卻能夠實現很多功能。(因為代碼文字呈現沒有格式,難以閱讀,以后小編提供的代碼都以截圖方式呈現,底部有源碼鏈接)。
到底多簡單,先來看代碼
基于jQuery
基于jQuery
拖拽實例圖:
拖拽實例圖
將代碼剝離,只要寫5行就可以實現拖拽了,是不是很簡單:
調用方式
放大、縮小
我們給拖拽增加點功能,支持放大、縮小,先看實例圖:
放大、縮小
將代碼剝離,原先的代碼保留不變,增加一個綁定事件:
放大、縮小
這樣來實現放大、縮小、拖拽是不是很簡單,還能實現很多其他效果,大家慢慢領悟。
原理分析:
放大、縮小、拖拽都離不開在網頁上拖動鼠標,對于前端來說就是 document 的 mousemove,當鼠標在網頁上移動的時候,無時無刻不在觸發 mousemove 事件,當鼠標觸發事件時,什么時候需要執行我們特定的操作,這就是我們要做的了。我在 mousemove 中增加了幾個對象來判定是否進行操作:
move:是否執行觸發操作
move_target:操作的元素對象
move_target.posix:操作對象的坐標
call_down:mousemove的時候的回調函數,傳回來的this指向document
call_up:當鼠標彈起的時候執行的回調函數,傳回來的this指向document
小提示:
簡單的操作,只需要設定 move_target 對象,設置 move_target 的時候不要忘記了 move_target.posix 哦;
復雜的操作可以通過call_down、call_up進行回調操作,這個時候是可以不用設置 move_target 對象的
深入研究
拖拽和放大、縮小實現了,但是有個問題,當我們鼠標點擊并滑動的時候,是會選中文本的,為了避免這個問題,大家可以自行百度
css 阻止文本選中
css 阻止文本選中
網頁的放大、縮小、拖拽事件就研究到這里了,小編不再對如何拓展進行深入講解,一切靠大家自行研究,權當課后作業了。~~
源碼鏈接地址:
http://orzcss.com/posts/d554a392/
本文內容均屬個人原創作品,轉載此文章須附上出處及原文鏈接。
加關注,定時推送,互動精彩多,若你有更好的見解,歡迎留言探討!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。