图片马赛克处理(Java)

news2024/9/22 23:39:14
1.需求
  • 给图片的指定区域打码
  • 给整张图片打码
  • 马赛克方格取色支持中心点取色和随机取色
  • 马赛克支持灰度处理
2.源码
package com.visy.utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Random;

/**
 * @author visy.wang
 * @date 2024/9/19 9:56
 */
public class ImageUtil {

    /**
     * 给图片指定区域打马赛克
     * @param x 打码区域左上角的横坐标
     * @param y 打码区域左上角的纵坐标
     * @param width 打码区域的宽度
     * @param height 打码区域的高度
     * @param size 马赛克格子尺寸,即每个正方形小方格的边长
     */
    public static void mosaic(
        InputStream source, OutputStream target, int x, int y, int width, int height, int size
    ) throws IOException {
        //读取该图片
        BufferedImage image = ImageIO.read(source);
        int imgWidth = image.getWidth(), imgHeight = image.getHeight();
        System.out.println("原图片尺寸:"+imgWidth+"*"+imgHeight);
        if(size<=0 || width==0 || height==0){
            //不打马赛克,直接返回原图
            ImageIO.write(image, "jpg", target);
            return;
        }

        //马赛克区域边界值处理
        width = width<0||width>imgWidth ? imgWidth : width;
        height = height<0||height>imgHeight ? imgHeight : height;

        //起点坐标<0处理
        x = Math.max(x, 0);
        y = Math.max(y, 0);

        //马赛克块大小 不能大于图片宽度和高度,超过时取宽高中小的那一个
        if (size > imgWidth || size > imgHeight) {
            size = Math.min(imgWidth, imgHeight);
        }

        //创建一张画布(和原图同尺寸,颜色类型选择RGB)
        BufferedImage canvas = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
        //获得画布的画笔
        Graphics gs = canvas.getGraphics();
        //先将原图片画到画布上
        gs.drawImage(image, 0, 0, null);

        //计算横向和纵向绘制马赛克方格的个数
        int xCount = width/size + (width%size==0 ? 0 : 1); //横绘绘制个数
        int yCount = height/size + (height%size==0 ? 0 : 1); //纵向绘制个数

        //遍历指定区域的所有方格并填充
        int $x = x;//方格左上角x坐标
        for (int i = 0; i < xCount; i++) {
            int $y = y;//方格左上角y坐标
            //方格的宽度,横向最后一个方格的宽需单独处理
            int $width = i==xCount-1 ? (x+width-$x) : size;
            for (int j = 0; j < yCount; j++) {
                //方格的高度,纵向最后一个方格的高需单独处理
                int $height = j==yCount-1 ? (y+height-$y) : size;
                //颜色取方格中心像素点RGB值
                //int rgb = getCenterRgb($x, $y, $width, $height, image);
                //颜色取方格内随机像素点RGB值
                int rgb = getRandomRgb($x, $y, $width, $height, image);
                //设置颜色(灰度处理)
                //Color color = new Color(toGray(rgb));
                Color color = new Color(rgb);
                //设置颜色
                gs.setColor(color);
                //填充方格
                gs.fillRect($x, $y, $width, $height);

                //方格加边框(用于测试)
                //gs.setColor(Color.RED);
                //gs.drawRect($x, $y, $width, $height);

                $y += size;//计算下一个方格的左上角y坐标
            }
            $x += size;//计算下一行方格的左上角x坐标
        }
        gs.dispose(); //释放资源
        ImageIO.write(canvas, "jpg", target); // 保存图片
    }

    /**
     * 给整张图片打马赛克
     * @param source 原图输入流
     * @param target 打码后的图片输出流
     * @param size 马赛克格子尺寸,即每个正方形小方格的边长
     */
    public static void mosaicAll(
        InputStream source, OutputStream target, int size
    ) throws IOException {
        mosaic(source, target, 0, 0, -1, -1, size);
    }

    /**
     * 获取马赛克小方格中心点的颜色
     * @param x 小方格左上角横坐标
     * @param y 小方格左上角纵坐标
     * @param width 小方格的宽度
     * @param height 小方格的高度
     * @param image 原图
     * @return 颜色RGB值
     */
    private static int getCenterRgb(int x, int y, int width, int height, BufferedImage image){
        //计算当前方格中心点位置
        int xCenterIndex = x + (width%2==0 ? width : width-1) / 2;
        int yCenterIndex = y + (height%2==0 ? height : height-1) / 2;
        //颜色取中心像素点RGB值
        return image.getRGB(xCenterIndex, yCenterIndex);
    }

    /**
     * 在马赛克小方格区域内随机取一个像素点的颜色
     * @param x 小方格左上角横坐标
     * @param y 小方格左上角纵坐标
     * @param width 小方格的宽度
     * @param height 小方格的高度
     * @param image 原图
     * @return 颜色RGB值
     */
    private static int getRandomRgb(int x, int y, int width, int height, BufferedImage image){
        //在方格区域内随机取一个点的颜色
        Random random = new Random();
        int xIndex = x + random.nextInt(width);
        int yIndex = y + random.nextInt(height);
        return image.getRGB(xIndex, yIndex);
    }

    /**
     * 彩色转换成黑白
     * @param rgb 彩色RGB值
     * @return 黑白RGB值
     */
    private static int toGray(int rgb){
        int r = (rgb >> 16) & 0xFF;
        int g = (rgb >> 8) & 0xFF;
        int b = rgb & 0xFF;
        // 计算灰度值
        int gray = (r + g + b) / 3;
        return (gray << 16) + (gray << 8) + gray;
    }

    /**
     * 创建目标(输出)文件
     * @param file 源文件
     * @return 目标文件
     */
    private static File createTargetFile(File file){
        String name = file.getName();
        String newName = name.substring(0, name.lastIndexOf("."))+"_mosaic.jpg";
        return new File(file.getParent(), newName);
    }

    public static void mosaic(File file, int x, int y, int width, int height, int size) throws IOException {
        InputStream in = Files.newInputStream(file.toPath());
        OutputStream out = Files.newOutputStream(createTargetFile(file).toPath());
        mosaic(in, out, x, y, width, height, size);
    }

    public static void mosaicAll(File file, int size) throws IOException {
        InputStream in = Files.newInputStream(file.toPath());
        OutputStream out = Files.newOutputStream(createTargetFile(file).toPath());
        mosaicAll(in, out, size);
    }

    public static void main(String[] args) throws IOException {
        File f = new File("E:\\test\\imgs\\2d6aa7e497a059df30d635667b1ec998.jpeg");
        //mosaic(f, 20 , 560, 500, 150, 10);
        mosaic(f,370, 241, 370, 245, 15);
        System.out.println("处理完成");
    }
}
3.输入输出
  • 处理前

在这里插入图片描述

  • 处理后(中心点取色)

在这里插入图片描述

  • 处理后(灰度处理)

在这里插入图片描述

  • 处理后(随机取色)

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

Rabbitmq消息队列,安装,使用,三种工作模式

产品 消息队列技术介绍 消息队列概述 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合、异步消息、流量削锋等问题。实现高性能、高可用、可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。 目前在生产环境&#xff0c;使用较多的消息队列有…

基于51单片机的汽车倒车防撞报警器系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 本课题基于微控制器控制器&#xff0c; 设计一款汽车倒车防撞报警器系统。 要求&#xff1a; 要求&#xff1a;1.配有距离&#xff0c; 用于把车和障碍物之间的距离信号送入控制器。 2.配有报警系…

2024AI做PPT软件如何重塑演示文稿的创作

现在AI技术的发展已经可以帮我们写作、绘画&#xff0c;最近我发现了不少ai做ppt的工具&#xff01;不体验不知道&#xff0c;原来合理使用AI工具可以有效的帮我们进行一些办公文件的编写&#xff0c;提高了不少工作效率。如果你也有这方面的需求就接着往下看吧。 1.笔灵AIPPT…

内网穿透out了?黑群晖+IPv6+NAS公网助手的访问体验

科技宅最带折腾黑群晖&#xff0c;这不&#xff0c;尝试一下ipv6动态域名解析&#xff0c;远程访问群晖NAS的方法千千万&#xff0c;这个方法我早就想到了&#xff0c;今天终于体验了一把&#xff0c;把经验分享一下&#xff1a; 目录 黑群晖的魅力 IPv6的加入&#xff1a;无…

Python办公自动化教程(003):PDF的加密

【1】代码 from PyPDF2 import PdfReader, PdfWriter# 读取PDF文件 pdf_reader PdfReader(./file/Python教程_1.pdf) pdf_writer PdfWriter()# 对第1页进行加密 page pdf_reader.pages[0]pdf_writer.add_page(page) # 设置密码 pdf_writer.encrypt(3535)with open(./file/P…

上位机图像处理和嵌入式模块部署(linux小系统开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 和若干年前相比较&#xff0c;现在嵌入式linux开发要简单得多。稍微贵一点的有树莓派&#xff0c;国产的有各种水果派&#xff0c;基本上都可以按照…

苍穹外卖学习日志 -----20天项目从零到完结-----含软件下载,环境配置,框架学习,代码编写,报错处理,测试联调,每日总结,心路历程等等......

年份 2024 基础&#xff1a;Javase Javaweb 已完结 2024 8.25---9.14 20天 Day-01 8.25 今天开始学习已经晚了&#xff0c;网盘下载了一下文件&#xff0c;做了一些开始项目的准备工作。 本来其实打算用notepad来写学习日志的&#xff0c;但是那个传…

如何给bat文件替换好看的图标

最近遇到软件运行在Windows系统&#xff0c;通过bat文件启动&#xff0c;但是bat文件的图标不好看&#xff0c;而且作为启动快捷方式放桌面看上去跟其他软件不搭调&#xff0c;于是得给bat文件换个软件图标。 软件ico图标 Windows系统下使用.ico文件作为软件图标。另外favicon…

go libreoffice word 转pdf

一、main.go 关键代码 完整代码 package mainimport ("fmt""github.com/jmoiron/sqlx""github.com/tealeg/xlsx""log""os/exec""path/filepath" ) import _ "github.com/go-sql-driver/mysql"import &q…

Python练习宝典:Day 1 - 选择题 - 基础知识

目录 一、踏上Python之旅二、Python语言基础三、流程控制语句四、序列的应用 一、踏上Python之旅 1.想要输出 I Love Python,应该使用()函数。 A.printf() B.print() C.println() D.Print()2.Python安装成功的标志是在控制台(终端)输入python/python3后,命令提示符变为: A.&…

数业智能心大陆:职场倦怠的新解法

什么是职业倦怠&#xff1f; 在职场中&#xff0c;职业倦怠的表现形式丰富多样。从数业智能心大陆 AI 心理咨询平台的数据来看&#xff0c;职业倦怠呈现出多种状态。教师可能对教学不再满怀热情&#xff0c;精心备课也成为过去式&#xff1b;情绪上容易烦躁、易怒&#xff0c;在…

【d47_2】【Java】【力扣】1791.找出星型图的中心节点

思路 直接判断 edges[0][0] edges[0][1] edges[1][0] edges[1][1] 谁重复了 例如&#xff1a; [ [1,2] [2,3] ....],那么中心节点一定是2 代码 class Solution {public int findCenter(int[][] edges) {for (int i0;i<1;i){if (edges[1][0]edges[0][i]) {return edg…

车载软件调试工具系列---Trace32简介UI界面简介

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

java项目之常规应急物资管理系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的常规应急物资管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息。 项目简介&#xff1a; 基于SpringBootVue的…

TikTok流量不佳:是网络环境选择不当还是其他原因?

TikTok&#xff0c;作为全球短视频社交平台的佼佼者&#xff0c;每天都有海量的内容被上传和分享。然而&#xff0c;很多用户和内容创作者发现&#xff0c;他们的TikTok视频流量并不理想。这引发了一个问题&#xff1a;TikTok流量不佳&#xff0c;是因为网络环境选择不当&#…

S3C2440定时器

ee一、构造 二、设置相关位 1、MPLLCON寄存器&#xff08;配置MPLL寄存器&#xff0c;进行倍频&#xff09; 根据下列表格的想要输出的频率进行选择&#xff0c;选择完毕之后&#xff0c;对该寄存器进行设置 2、时钟分频控制&#xff08;CLKDIVN&#xff09;寄存器 根据不…

AD19基础应用技巧:交叉选择/跳转到器件/镜像粘贴/元器件矩形区域排列/选择过滤器/捕捉对象等设置

目录 1. 原理图<>PCB跳转2. 镜像粘贴3. 矩形区域排列4.选择过滤器5. 捕捉的对象Object for Snapping的设置 6.Grids/Guides/Axes1. **Grids&#xff08;网格&#xff09;**2. **Guides&#xff08;参考线&#xff09;**3. **Axes&#xff08;坐标轴&#xff09;**捕捉模式…

基于python的文本聚类分析与可视化实现,使用kmeans聚类,手肘法分析

1、数据预处理 由于在数据分析之前数据集通常都存在数据重复、脏数据等问题&#xff0c;所以为了提高 数据分析结果的质量&#xff0c;在应用之前就必须对数据集进行数据预处理。数据预处理的方法通常有清洗、集成、转换、规约这四个方面&#xff0c;接下来详细介绍这对爬取…

学习记录:js算法(四十二): 寻找两个正序数组的中位数

文章目录 寻找两个正序数组的中位数我的思路网上思路 总结 寻找两个正序数组的中位数 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,3], n…

力扣72-编辑距离(Java详细题解)

题目链接&#xff1a;力扣72-编辑距离 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 dp五部曲。 1.确定dp数组和i下标的含义。 2.确定递推公式。 3.dp初始化。 4.确定dp的遍历顺序。 5.如果没有ac打印dp数组 利于debug。 每一个dp…