基于processing的图片处理app(伪)教程

项目课(计算机)

前言

Fuck Hanhe
建议是有些许计算机基础的来看,数学系的学生可以先学下c++的基本语法(b站搜索黑马程序员),这个大二要学。
前置知识是 函数,变量,循环语句和判断语句。
c2成功坠机,感觉第二次做的那个比第一个好太多了。
没办法,至少第二个做的时候有人给你美术图片,第一个发消息在群里征询美术意见都没声音的。
室友拿了b3,一个朋友拿了b2,他们的程序看起来就friendly些。


是应数的计算机周会很坑爹,微积分期中考,4级考试,3k字的新生课(军训推迟上课但提交报告时间没推迟)
建议小组是两个程序,一个美化,一个视频,一个文案。
不要像我一样一个人把程序美化全包了
本篇教程不会让你得很高的分,只是让你更快的学些有用的东西
所以关于教学processing的部分很简单,是让你对着书看的
窗口大小建议设置小点,否则后面改起来很痛苦,很多人的电脑并不是2560的
不要像lhh一样我写了前言又不看,直奔主题又说自己看不懂,我真的无语。
里面()多是我想让你手打()
有错误和意见请批评指正,多谢啦!(*´・ω・`)⊃,我会一步步完善的。

processing基础部分

真心想学好的可以看我资源分享里的书(中文),看完1——9章下面只是一些简单的东西
英文版
https://ebookcentral.proquest.com/lib/dundee/detail.action?docID=4333729
我下面的也只能给有基础的看感觉(否则我也有写书的水平了,乐)
第一次可以先用ai生成几个实例或者看processing自带样板来熟悉一下这门语言

下载processing

好多同学卡在第一步下载了,一般是要梯子去github下的,如果是计算机系的要早点准备了,github将是你的一个很关键的平台,用来学习找项目什么的。
在后面的资源分享(自愿返乡)里有win版的
设置里可以调中文和字体大小,不要像我一样在最后才知道。

一般用法

程序由若干个函数组成,而程序语句只能在函数中调用。
Processing 提供大量预定义函数,直接调用即可,本文会讲到一些与图片处理相关的。
setup() 函数:程序启动时运行一次,用于初始化窗口大小、背景色等。
draw() 函数:每秒默认运行 60 次(帧率可调),用于持续更新画面。
通俗来讲,点击运行,首先setup()就会执行里面的语句,在执行完后就会进入draw()的循环执行中。
ai样例

void setup() {
  size(800, 600); // 窗口尺寸
  background(255); // 背景色(白色)
}

void draw() {
  ellipse(mouseX, mouseY, 50, 50); // 跟随鼠标画圆
}

数据类型

我们会把数据储存到变量中,而每个变量都有其数据类型,计算机将会根据其类型来分配不同的内存来储存。

知道这些就行
int是整数、float是小数、PImage是图片
String是文字,需要用""括起来,如"i am die"
boolean 是 布尔类型, 储存的是truefalse掌控逻辑判断

类型 名字; //不带赋值
类型 名字 = 值; //带赋值


数组
就是要存储多个intfloat时要用到的,连续储存不同数据的结构。
注意数组是从0开始计算的。定义一个大小为2的int数组a,里面只有a[0]a[1]

类型[] 名字;
类型[]名字 = new 类型[数量];


动态数组
可以通过 ArrayList 类来实现。ArrayList 是 Java 集合框架的一部分,它提供了动态调整大小的数组功能,这意味着你不需要在创建时指定数组的大小,并且可以在运行时添加或删除元素。
更多的自行了解,资料比processing多太多了

import java.util.ArrayList;
void setup(){
	// 创建一个存储整数的 ArrayList
	ArrayList<Integer> numbers = new ArrayList<>();
	// 或者指定初始容量
	ArrayList<String> words = new ArrayList<>(10);
	main();
}

void main(){
	numbers.add(1); //增加数组元素
	int a = numbers.get(0); //访问数组元素,0是下标
	numbers.remove(0); //移除索引为0的袁术
	numbers.add(1); //增加数组元素
	numbers.set(0, 50); // 将索引 0 处的元素更新为 50
	int size = numbers.size(); // 获取当前元素数量
	// 使用增强的 for 循环
	for (Integer num : numbers) {
		System.out.println(num);
	}
}

运算符

+-*/ 分别是加、减、乘、整除
= 是赋值不是相等

boolean类型运算符包括&&(短路与,都为正确才正确)、
||(短路或,有一个正确就正确)、
!(非,取反面)、

| == | 等于 |
| != | 不等于 |
| > | 大于 |
| < | 小于 |
| >= | 大于或等于 |
| <= | 小于或等于 |

语句

学会 if、for循环就行,骚年,百度吧!看我代码也行


if (条件) {
    // 当条件为真时执行的代码块
}

if (条件1) {
    // 当条件1为真时执行的代码块
} else if (条件2) {
    // 当条件1为假且条件2为真时执行的代码块
} else {
    // 当所有条件都不满足时执行的代码块
}

for (初始化; 条件; 迭代) {
    // 每次循环要执行的代码块
}

像素

理解为带颜色的坐标点就行,不断密集就形成了图像。具体的百度了解。
左上角是坐标原点,往右是x轴,往下是y轴

可以先写个void mousePressed(){println(mouseX+","+mouseY);}来熟悉一下
其中mouseX是鼠标点击的横坐标,mouseY是鼠标点击的纵坐标
void mousePressed(){代码块}是函数的形式,是processing自带的用来监视鼠标点击的
类似的还有

void mouseReleased(){代码块}:当鼠标按钮释放时调用。
void mouseClicked(){代码块}:当鼠标点击(按下并释放)时调用。
void mouseMoved(){代码块}:当鼠标移动且没有按钮被按下时调用。
void mouseDragged(){代码块}:当鼠标移动且有按钮被按下时调用。
void mouseWheel(){代码块}:当鼠标滚轮滚动时调用。

有RGB和HSV两种系统用colorMode(HSB)colorMode(RGB)可以切换
这也是实现亮度,透明度和饱和度的关键

HSV (色相hue, 饱和度saturation, 明度value), 也称HSB

// 设置颜色模式为 HSB 并定义每个分量的最大值
 colorMode(HSB, 360, 100, 100, 100); 
 // 最后一个参数是 alpha (透明度)的最大值

// 使用 HSB 定义颜色并包含透明度 (alpha)
 fill(240, 80, 60, 50); // 蓝色,中等饱和度,低亮度,半透明
 rect(50, 50, 100, 100);

透明度我是用tint(value)noTint()实现的,0~255的透明度数值value

line、rect、text


其实可以没必要掌握,让美工在画图上画好,自己在打判定点就行,为啥要用processing画图???当然这是有必要掌握的(其他数学软件),但在实现图像编辑器的时候没用。

stroke(Ccolor) //设置边的颜色
noStroke() //消去边

可以设置边的颜色,Ccolor我记得是填颜色对应的数字,0是黑,255是白,还有用网络编码的##FFC0CB(粉红)

fill(Ccolor) //里面的填充色
nofill(); //没有填充

设置内部颜色

line(起始点x,起始点y,结束点x,结束点y)

用不到一点

rect(起始点x,起始点y,长,宽)

第一种,我用的最多

rextMode(CENTER)
rect(中心点x,中心点y,长,宽)

没用过,防查重可以

text(文本内容,起始点x,起始点y)
textSize(字体大小)
textLeading(行距)
textAlign(halign, valign); //下面贴AI详解

halign: 水平对齐方式,可以是以下之一:
    LEFT (默认):文本的左边缘与给定的 x 坐标对齐。
    CENTER:文本的水平中心与给定的 x 坐标对齐。
    RIGHT:文本的右边缘与给定的 x 坐标对齐。
valign: 垂直对齐方式,可以是以下之一:
    BASELINE (默认):文本的基线(字母的底部线)与给定的 y 坐标对齐。
    TOP:文本的顶部与给定的 y 坐标对齐。
    CENTER:文本的垂直中心与给定的 y 坐标对齐。
    BOTTOM:文本的底部与给定的 y 坐标对齐。

文本内容是String类型的
最难调控的一个,往往调这个的坐标用一上午还搞不好,可惜没早点知道画图解决就行,tip区还是要用text的我真的。

但文本功能是必用的。

参数

mouseX,mouseY是鼠标的坐标
displayWidth 和 displayHeight 是屏幕大小
width 和 height 是窗口大小

图像

PImage 图像名 = loadImage("文件名.文件类型"); //载入图片
image(图像名,起始点x,起始点y); //展示图片
image(图像名,起始点x,起始点y,长,宽); //有放缩的展示图片
get(x,y,长,宽) //获取窗口上显示的像素,返回类型是PImage
图像名.save("modified_example.png"); // 将图像保存为 PNG 文件

下面展示了对图片的像素级操作

img.loadPixels();
colorMode(HSB);
for (int i = 0; i < img.pixels.length; i++) {
  color c = img.pixels[j];
        float h = hue(c);
        float s = saturation(c)*saturationNum[nowUsing]/100;
        float b = brightness(c)*brightnessNum[nowUsing]/100;
        img.pixels[j] = color(h, s, b);
}
img.updatePixels();
colorMode(RGB);

函数

计算机的建议看书自学,下面只是简单介绍下

点击查看代码
/*返回类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, ...) {
    // 函数体
}
*/

void main(String[]args){
    // 函数体
}

/*这个就是函数的形式,返回值类型就是使用函数后所留下的值
  比如 x = sin(0), sin()就是一个函数,其中0就是参数,返回的值就是sin(0)的值0
  所以 x被赋上了0的值
  参数列表中的变量用于接收调用该函数或方法时传递的值,使得函数能够根据外部提供的数据执行特定的操作。
  在实践中就会知道的,应篇幅原因大头放在代码思路,不懂建议百度
*/
//使用就是
  main();
//main里面的代码就会执行啦


那先来介绍不同于JAVA的部分,没有了main(),而是setup()和draw()
其实还有个settings()

执行一遍的setup,我们要来做什么呢?
简而言之就是初始化,设置背景,加载图片,构建对象,初始化数组等等一次性功能都可以放上去。

void setup() {
  size(800, 600); // 创建一个 800x600 像素的窗口
  
  // 加载图片和字体
  //在同文件夹下面就行,一般是放在名字为data的子文件夹下
  img = loadImage("myImage.jpg"); 
  font = createFont("Arial", 32);
  
  // 设置颜色模式
  colorMode(HSB, 360, 100, 100);
  
  // 设置背景颜色
  background(240, 80, 60); // 使用 HSB 模式设置背景色为蓝色,中等饱和度,低亮度
  
  //设置回来
  colorMode(RGB);

  // 设置文本
  textFont(font);
  fill(255); 
  noStroke(); 
  
  // 打印一条消息到控制台作为Debug
  println("Setup completed.");
}

void draw() {
  // 主循环代码放在这里
  //可以用loop(),noLoop()来优化循环,节省资源,但是我懒所以我的代码都没这样做。
  //详细点的请看代码实现
}

关于map()、constrain()等等函数可以自行了解,我觉得用map实现百分比,constrain实现限制挺不错的。

代码实现思路

先规划好程序整体框架,哪个部分是图片展示,哪个部分是tip区,哪个部分是操作区等等
等你队友画好图再开始写一些判定的指令,然后写一些效果的实现



注释打在函数体里,介绍函数功能和参数列表的变量的含义
尽量有tip,display,work三个区
而且从写代码前就分开,写代码时也互不影响
林瀚和要的保存我记得是保存display展示的区域,get就行。

判定点

拿到图后敲判定点

if(mouseX > real_x && mouseX < real_x + real_width &&   
  mouseY > real_y && mouseY < real_y + real_height &&){
  //鼠标放上去的操作,比如实现图片动态,出现tip
}
void MousePressed(){
  if(mouseX > real_x && mouseX < real_x + real_width &&   
  mouseY > real_y && mouseY < real_y + real_height &&){
  //鼠标点上去的操作,实现什么功能
  }
}

切换背景图

重新加载张新图片就行

载入图片、展示图片、保存图片

可以用数组,大小设置大点就是了。用img_cnt记录图片数量
动态数组也行,我就是。

selectInput("Select an image file:", "ImgSelect");
出现一个窗口,"Select an image file:"是窗口标题,"ImgSelect"是调用的函数如下

void ImgSelect(File path) {
//传递了文件path
  println("Select the path of the new image you want to use");
  if (path == null) {
    println("You selected nothing");
    return;
  }
//将File path转化为String paths,取的是绝对路径
  String paths = path.getAbsolutePath();
//图片载入
  PImage tmp = loadImage(paths);
  if (tmp == null) {
    println("Failed to load the new image");
  } 
  else {
    println("Loaded image: " + paths);
    images.add(tmp);
    lastImages.add(tmp);
    originalImages.add(tmp);
    nowUsing++;
  }
  println("The new image from " + path);
  x[nowUsing] = 250;
  y[nowUsing] = 0;
  calculateSize();
}

同理保存也可以这么实现用if和boolean分开就行

打印图片可以每次操作打印一次,用一个布尔类型is_act就行。
我没这样做,我懒(*´・ω・`)⊃
display赛在draw里一直在打印

void display(){
   //打印图片
  if (nowUsing == -1) return; //跳过当前图片
  
  for(int i = 0; i < images.size(); i++) {
    if (i == nowUsing) continue;
    //设置效果范围pushMatrix()、popMatrix()
    //display_x,display_y 显示区左上点,fine_x,fine_y 合适大小

    pushMatrix();
    //加载图片、效果处理
    image(img, display_x,display_y,fine_w,fine_h);
    popMatrix();

  }
  

   
  //设置效果范围pushMatrix()、popMatrix()
  //display_x,display_y 显示区左上点,fine_x,fine_y 合适大小

  pushMatrix();
  //加载当前图片、效果处理
  image(img, display_x,display_y,fine_w,fine_h);
  popMatrix();
  
}

滑条

样子自己用两个矩形手搭建一个吧,一个矩形的位置跟着变动就行。
拖动就是弄个布尔变量draggingmouseDragged()根据位置改变值就行,判定还挺难打的。

图片效果

  • 旋转:rotate()
  • 移动:改变坐标
  • 截切:get()获取PImage就行
  • 放缩:PImageresize方法很可以,或者scale()
    但是很可怕的一点,rotate和scale都会改变坐标系,怎么变回来请读者自证

PImage.filter()是很重要的一个实现

filter(kind)
filter(kind, param)
kind:这是你想要应用的效果类型。它可以是以下预定义常量之一:
    THRESHOLD:将图像转换为黑白二值图像,使用可选参数作为阈值(0.0 到 1.0)。默认值为 0.5。
    GRAY:将图像转换为灰度图像。
    INVERT:反转图像的颜色。
    OPAQUE:使图像中的透明部分变为不透明。
    BLUR:应用高斯模糊效果。可选参数控制模糊的程度,默认值为 1。
    ERODE:减少亮区域的大小,通常用来消除小的亮点。
    DILATE:增加亮区域的大小,通常用来增强图像中的亮点。
param:这是一个可选参数,某些滤镜效果需要额外的参数来调整其强度或特性,如上述提到的 THRESHOLD 和 BLUR。

高级策略

Graphics()

使用Graphics可以用来实现多图层,我没怎么用的上大家可以自己想想。
文字一个图层,不同图片不同图层这样子的。
贴两个介绍

https://vimsky.com/examples/usage/processing-PGraphics-pr.html
https://processing.org/reference/pgraphics

controlp5

在 Processing IDE 中安装,导入ControlP5 库,
林瀚和这个xx,最后一节课才给你讲,服了。通宵把几个可能有用的对象学了一下,AI给的东西基本都是和JAVA混在一起了,你要想学明白只能看examples。
我用这个实现了一个图像编辑器,在资源分享里。

Download controlP5

  • [1]Open Processing.
  • [2]Follow the Sketch -> Import Library -> Add Library
  • [3]Search ControlP5 and install it.


初始化
import controlP5.*;
ControlP5 cp5;
void setup() {
  size(888, 888);
  cp5 = new ControlP5(this); // 初始化 ControlP5
}

构建按钮

cp5.addButton("Load")     //增加对象
     .setPosition(70, 5)   //设置位置,左上角
     .setSize(110, 110)    //判定大小
     .setImage(loadIcon)   //增加图片,可以没有,按钮上的就是label了
     .setLabel("Load");    //重新给label命名,不是给对象命名

//获取按钮的label并进行设置。
cp5.getController("Load")
.getCaptionLabel()
.setFont(createFont("Arial", 30))         //Front
.align(ControlP5.CENTER, ControlP5.CENTER)  //位置

构建滑条(有2维的可以自己摸索)

//和按钮几乎同理
cp5.addSlider("slider")
     .setPosition(10,30)
     .setSize(230,40)
     .setRange(0,360)
     .setValue(0)
     ;

//“slider”是滑条名字,下面代码来自官方样例

//改变滑条名字label
cp5.getController("slider")
.getValueLabel()
.align(ControlP5.LEFT, ControlP5.BOTTOM_OUTSIDE)
.setPaddingX(0);

//改变滑条值label
cp5.getController("slider")
.getCaptionLabel()
.align(ControlP5.RIGHT, ControlP5.BOTTOM_OUTSIDE)
.setPaddingX(0);

窗口

可以用java带的窗口或processing自带的窗口实现更friendly的交互。

资源分享

要借鉴随便,查重能过就行
通过网盘分享的文件:资源分享
链接: https://pan.baidu.com/s/1kHhoRknMwbB0phsjGCTYuw?pwd=DICU 提取码: DICU

骂人

点击查看代码
写这段的理由是为了纪念神人林汉翮,程序写了段introduction他说字太多没人会看,进界面又说会有看不懂操作的人,呃呃那我introduction写了干嘛,后面全删了呃呃。
林汉翮,在交草案的前一节课教你最有用的 controlP5 结果教出来还是一坨的人。到最后发现这些都不重要,重要的是你的界面和code风格能不能让他满意。举他女儿12岁做的程序玩具来说所有人都能做到真给我整乐了,我10岁在乡下自学JAVA做好了个仓库管理系统,15岁在高中做个介绍黑茶app加pre也没给你上嘴脸啊。有些东西没教就问你会不会,这个我认,大学是自学的地方,但我说我会你又说怎么没用,说我不会又要叫你怎么不会自学真忍不了。

请新同学们注意,他就是个类人,为什么不顺从他呢。你写的程序必须让这个智力明显低于一般水平的人看的懂,每个地方要详细到泰迪都会用,建议摆烂,反正又有会干代码的人被他气乐的。这东西还有叫到,服了。真当每个学生都是程序员,我又不是计科的?PUA牛魔呢,真气乐了。建议别学,ai跑跑得了,对之后没有一点用。

希望他代码水平比嘴上强。能21天自学实现他这要求那为啥不去大厂上班呢,问我难道这是你一个做的吗我只能呃呃,毕竟我只有0.5个人做这个。
学完后你发现啥都没学到。没提前学过其他程序的真的听得懂他的建议吗。这么多人摆烂连程序都看不懂他不知道是他的问题?任务好做点会有人找外包?羡慕纯零基础努力三周学这个东西认认真真自己写代码,结果还要被说的同学,太爽了。
如果你觉得口气重了确实是我的问题,毕竟3天来我睡两小时拯救两组人,今晚估计又是个不眠夜。
posted @ 2024-12-22 17:30  Tenryon  阅读(104)  评论(0)    收藏  举报