Java实现油画滤镜效果【参数可调】

news2024/10/19 6:33:24

油画滤镜的基本原理

油画滤镜的基本思想是通过改变图像的像素,将每个像素用周围随机选择的像素来代替,从而产生类似油画笔触的效果。这种处理方式可以模糊图像的细节,使得图像的色块更加连贯,从而模仿油画的艺术效果。

核心步骤

  1. 局部颜色随机替换:在图像中,每个像素点用其周围的某个随机像素的颜色代替,以模拟油画中笔刷带来的随机性和纹理。
  2. 多线程并发处理:使用Java的多线程技术同时处理多个区域的像素点,提升处理大图像的效率。

实现油画滤镜的Java代码

接下来是具体的实现代码,使用了Java的图像处理库BufferedImage,并通过多线程加快图像的处理速度。

代码示例

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MultiThreadedOilPaintEffect {

    public static void main(String[] args) throws IOException {
        // 读取输入图像
        BufferedImage inputImage = ImageIO.read(new File("原始图片"));

        // 创建文件夹保存图像
        String outputDir = "保存路径";
        File dir = new File(outputDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 创建一个固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(10); // 假设4个线程

        // 遍历 radius 从 1 到 8
        for (int radius = 2; radius <= 2; radius++) {
            // 遍历 intensityLevel 从 50 到 300,步进为 10
            for (int intensityLevel = 24; intensityLevel <= 50; intensityLevel += 4) {
                int finalRadius = radius;
                int finalIntensityLevel = intensityLevel;

                // 提交任务到线程池
                executor.submit(() -> {
                    try {
                        processAndSaveImage(inputImage, finalRadius, finalIntensityLevel, outputDir);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
            }
        }

        // 关闭线程池
        executor.shutdown();
    }

    // 处理图像并保存
    private static void processAndSaveImage(BufferedImage inputImage, int radius, int intensityLevel, String outputDir) throws IOException {
        // 将图像转换为油画效果
        BufferedImage outputImage = applyOilPaintEffect(inputImage, radius, intensityLevel);

        // 保存结果图像到桌面指定文件夹
        String outputFilePath = outputDir + radius + "-" + intensityLevel + ".png";
        ImageIO.write(outputImage, "png", new File(outputFilePath));

        System.out.println("已保存:" + outputFilePath);
    }

    // 应用油画效果
    private static BufferedImage applyOilPaintEffect(BufferedImage inputImage, int radius, int intensityLevel) {
        int width = inputImage.getWidth();
        int height = inputImage.getHeight();

        BufferedImage outputImage = new BufferedImage(width, height, inputImage.getType());

        // 将彩色图像转换为灰度图像
        int[][] grayImage = new int[width][height];
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                Color color = new Color(inputImage.getRGB(x, y));
                int gray = (int) (color.getRed() * 0.299 + color.getGreen() * 0.587 + color.getBlue() * 0.114);
                grayImage[x][y] = (gray * intensityLevel) / 255;
            }
        }

        // 应用油画效果
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                int[] intensityCounter = new int[intensityLevel + 1];
                int[] sumR = new int[intensityLevel + 1];
                int[] sumG = new int[intensityLevel + 1];
                int[] sumB = new int[intensityLevel + 1];

                for (int i = x - radius; i <= x + radius; i++) {
                    for (int j = y - radius; j <= y + radius; j++) {
                        if (i >= 0 && i < width && j >= 0 && j < height) {
                            int intensity = grayImage[i][j];
                            intensityCounter[intensity]++;
                            Color color = new Color(inputImage.getRGB(i, j));
                            sumR[intensity] += color.getRed();
                            sumG[intensity] += color.getGreen();
                            sumB[intensity] += color.getBlue();
                        }
                    }
                }

                // 找到最大频率的灰度值
                int maxCount = 0;
                int selectedIntensity = 0;
                for (int k = 0; k <= intensityLevel; k++) {
                    if (intensityCounter[k] > maxCount) {
                        maxCount = intensityCounter[k];
                        selectedIntensity = k;
                    }
                }

                // 计算该强度下的平均颜色
                int avgR = sumR[selectedIntensity] / maxCount;
                int avgG = sumG[selectedIntensity] / maxCount;
                int avgB = sumB[selectedIntensity] / maxCount;

                // 设置输出图像的像素颜色
                outputImage.setRGB(x, y, new Color(avgR, avgG, avgB).getRGB());
            }
        }

        return outputImage;
    }
}

可以根据不同的radius和intensityLevel参数调整生成范围,从而筛选出自己最想要的那种图片


这里我生成了7长图片,效果如下:

原始图

生成图:

 

如果再加大radius则会保留更少细节,根据自己实际情况调整参数去动态生成即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2218295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

后台管理员登录实现--系统篇

我的小系统后台原来就有一个上传图片的功能还夹带个删除图片的功能&#xff0c;还嵌到了一个菜单里面。之前效果如下 那么现在为了加大安全力度&#xff0c;想增加一个登录页面。通过登录再到这个页面。看着貌似很简单&#xff0c;但是听我细细说来&#xff0c;要新增些什么东西…

OpenLayers:构建现代Web地图应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 OpenLayers&#xff1a;构建现代Web地图应用 文章目录 OpenLayers&#xff1a;构建现代Web地图应用1. 简介2. 为什么选择 OpenLa…

Redis 高可用:从主从到集群的全面解析

目录 一、主从复制 (基础)1. 同步复制a. 全量数据同步b. 增量数据同步c. 可能带来的数据不一致 2. 环形缓冲区a. 动态调整槽位 3. runid4. 主从复制解决单点故障a. 单点故障b. 可用性问题 5. 注意事项a. Replica 主动向 Master 建立连接b. Replica 主动向 Master 拉取数据 二、…

腾讯云宝塔面板前后端项目发版

后端发版 1. 打开“网站”页面&#xff0c;找到java项目&#xff0c;点击状态暂停服务 2.打开“文件”页面&#xff0c;进入jar包目录&#xff0c;删除原有的jar包&#xff0c;上传新jar包 3. 再回到第一步中的网站页面&#xff0c;找到jar项目&#xff0c;启动项目即可 前端发…

C#的小数位保留以及四舍五入

C#使用Math.Round("数值","保留位","保留方式")进行小数位保留以及四舍五入 //1.MidpointRounding.ToEven(四舍六入五成双) //当保留小数位后一位为0~4时&#xff0c;舍去末位 var x1 Math.Round(1.124, 2, MidpointRo…

立仪科技:光谱共焦传感器精准测量玻璃

光谱共焦测量技术作为一种创新的光学检测方法&#xff0c;近年来在工业领域引起了广泛关注。 它以其高精度、非接触式的特点&#xff0c;特别适用于透明或半透明材料如玻璃的厚度和表面形貌测量。 接下来&#xff0c;立仪科技小编将深入探讨光谱共焦技术在玻璃测量上的应用及其…

计算机毕业设计Hadoop+Hive+Spark+Flink广告推荐系统 广告预测 广告数据分析可视化 广告爬虫 大数据毕业设计 深度学习 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 专业 小四号宋体 班级 小…

飞机大战告尾

参考 PPO算法逐行代码详解 链接 通过网盘分享的文件&#xff1a;PlaneWar 链接: https://pan.baidu.com/s/1cbLKTcBxL6Aem3WkyDtPzg?pwd1234 提取码: 1234 10.17关于博客发了又改这件事 悲催的事 今天训练了一早上ppo模型&#xff0c;满怀期待的检测成果时发现一点长进都…

mac安装brew时踩坑解决方案

安装包 mac上如果按照git等工具可能会使用brew&#xff0c;例如使用&#xff1a;$ brew install git命令&#xff0c;如果电脑没有按照brew&#xff0c;则会提示&#xff1a;zsh: command not found: brew 解决方案 需要我们打开brew的官网https://brew.sh/&#xff0c;复制…

动态规划一>下降路径最小和

1.题目&#xff1a; 2.解析&#xff1a; 代码&#xff1a; /**1.创建dp表2.初始化3.填表4.返回值*/public int minFallingPathSum(int[][] matrix) {int n matrix.length;int[][] dp new int[n1][n2];int minNum Integer.MAX_VALUE; for(int i 1; i < n; i) dp[i][0]…

【CSS】纯CSS Loading动画组件

<template><div class"ai-loader-box"><!-- AI loader --><div class"ai-loader"><div class"text"><p>AI智能分析中....</p></div><div class"horizontal"><div class&quo…

简单说说 spring是如何实现AOP的(源码分析)

在spring生命周期流程中&#xff0c;有一个过程是执行BeanPostProcessor的后置方法 BeanPostProcessor 是一个接口&#xff0c;其实现有 aop实现的核心类是AbstractAutoProxyCreator&#xff0c;其位于spring-aop包下&#xff0c;实现了BeanPostProcessor //BeanPostProcesso…

【Java小白图文教程】-04-分支结构

本套课程将会从0基础讲解Java语言核心技术&#xff0c;适合人群&#xff1a; 大学中开设了Java语言课程的同学想要专升本或者考研的同学想要考计算机等级证书的同学想要从事Java相关开发开发的同学 精品专题&#xff1a; 01.《C语言从不挂科到高绩点》课程详细笔记 https:/…

transformers 推理 Qwen2.5 等大模型技术细节详解(一)transformers 初始化和对象加载(文末免费送书)

上周收到一位网友的私信&#xff0c;希望老牛同学写一篇有关使用 transformers 框架推理大模型的技术细节的文章。 老牛同学刚开始以为这类的文章网上应该会有很多&#xff0c;于是想着百度几篇质量稍高一点的回复这位网友。结果&#xff0c;老牛同学搜索后发现&#xff0c;类…

力扣61~65题

题61&#xff08;中等&#xff09;&#xff1a; 分析&#xff1a; python代码&#xff1a; # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def rot…

【含开题报告+文档+PPT+源码】基于SpringBoot电脑DIY装机教程网站的设计与实现

开题报告 随着科技的发展和人们对电脑需求的增加&#xff0c;越来越多的人开始自己组装电脑。然而&#xff0c;针对初学者来说&#xff0c;如何选择合适的硬件配置并进行装机是一个相对复杂的过程。随着各种品牌、型号和规格的硬件不断增多&#xff0c;用户需要一个方便快捷的…

Java项目编译不通过,IDEA无法运行或调试Unit test类

mvn test可以通过&#xff0c;但是通过IDEA无法运行或调试&#xff0c;总是弹出一些依赖错误比如&#xff1a; 程序包xxx.xxx.xxx 不存在或找不到符号 解决办法 步骤1&#xff1a;IDEA 打开 File -> Setting ->Compiler &#xff0c;找到“Automatically show first …

20 Shell Script输入与输出

标出输入、标准输出、错误输出 一、程序的基本三个IO流 一&#xff09;文件描述符 ​ 任何程序在Linux系统中都有3个基本的文件描述符 ​ 比如: ​ cd/proc/$$/fd ​ 进入当前shell程序对于内核在文件系统的映射目录中: [rootlocalhost ~]# cd /proc/$$/fd [rootlocalhos…

基于System.js的微前端实现(插件化)

目录​​​​​​​ 写在前面 一、微前端相关知识 &#xff08;一&#xff09;概念 &#xff08;二&#xff09; 优势 &#xff08;三&#xff09; 缺点 &#xff08;四&#xff09;应用场景 &#xff08;五&#xff09;现有框架 1. qiankun 2. single-spa 3. SystemJ…

【MR开发】在Pico设备上接入MRTK3(一)——在Unity工程中导入MRTK3依赖

写在前面的话 在Pico上接入MRTK3&#xff0c;目前已有大佬开源。 https://github.com/Phantomxm2021/PicoMRTK3 也有值得推荐的文章。 MRTK3在PICO4上的使用小结 但由于在MacOS上使用MRTK3&#xff0c;无法通过Mixed Reality Feature Tool工具管理MRTK3安装包。 故记录一下…