图像处理之错切变换

简介: 图像处理之错切变换一:基本数学知识:图像错切变换在图像几何形变方面非常有用,常见的错切变换分为X方向与Y方向的错切变换。对应的数学矩阵分别如下:  根据上述矩阵假设P(x1, y1)为错切变换之前的像素点,则错切变换以后对应的像素P’(x2, y2)当X方向错切变换时:当Y方向错切变换时:二:程序实现基本思路实现图像错切变换时,必须考虑图像将目标像素点坐标变为源相点坐标时小数部分对像素值的影响,这里通过临近点插值算法实现了目标像素值的计算。

图像处理之错切变换

一:基本数学知识:

图像错切变换在图像几何形变方面非常有用,常见的错切变换分为X方向与Y方向的

错切变换。对应的数学矩阵分别如下:

  

根据上述矩阵假设P(x1, y1)为错切变换之前的像素点,则错切变换以后对应的像素

P’(x2, y2)当X方向错切变换时:


当Y方向错切变换时:


二:程序实现基本思路

实现图像错切变换时,必须考虑图像将目标像素点坐标变为源相点坐标时小数部分对

像素值的影响,这里通过临近点插值算法实现了目标像素值的计算。根据目标像素计

算源像素的公式可以根据上面的数学公式运算以后分别求的x1,y1的值。由于错切以

后图像会在宽或者高上比原图像大,多出来的这些背景像素默认填充颜色为黑色。

类ShearFilter实现了图像水平或者垂直方向的错切变换,支持角度与背景颜色参数

设置。

 三:编程关键点解析

Ø  计算错切以后图像的宽与高

        double angleValue = (angle/180.0d) * Math.PI;
        outh = vertical ? (int)(height + width * Math.tan(angleValue)) : height;
        outw = vertical ? width : (int)(width + height * Math.tan(angleValue));
        System.out.println("after shear, new width : " + outw);
        System.out.println("after shear, new height: " + outh);
Ø  根据目标像素点坐标计算源像素点坐标

	double prow = vertical ? row + Math.tan(angleValue) * (col - width) : row;
	double pcol = vertical ? col : col + Math.tan(angleValue) * (row - height);
        int[] rgb = getPixel(inPixels, width, height, prow, pcol);

Ø  临近点插值计算目标像素点像素值

private int[] getPixel(int[] input, int width, int height, 
		double prow, double pcol) {
	double row = Math.floor(prow);
	double col = Math.floor(pcol);
	if(row < 0 || row >= height) {
		return new int[]{backgroundColor.getRed(), 
				backgroundColor.getGreen(), 
				backgroundColor.getBlue()};
	}
	if(col < 0 || col >= width) {
		return new int[]{backgroundColor.getRed(), 
				backgroundColor.getGreen(), 
				backgroundColor.getBlue()};
	}
	double u = vertical ? (prow - row) : pcol - col;
	int nextCol = (int)(col + 1);
	int nextRow = (int)(row + 1);
	if((col + 1) >= width) {
		nextCol = (int)col;
	}
	if((row + 1) >= height) {
		nextRow = (int)row;
	}
	int index1 = (int)(row * width + col);
	int index2 = vertical ? (int)(nextRow * width + col) : (int)(row * width + nextCol);
	
	int tr1, tr2;
	int tg1, tg2;
	int tb1, tb2;
	
    tr1 = (input[index1] >> 16) & 0xff;
    tg1 = (input[index1] >> 8) & 0xff;
    tb1 = input[index1] & 0xff;
    
    tr2 = (input[index2] >> 16) & 0xff;
    tg2 = (input[index2] >> 8) & 0xff;
    tb2 = input[index2] & 0xff;
    
    int tr = (int)(tr1 * (1-u) + tr2 * u);
    int tg = (int)(tg1 * (1-u) + tg2 * u);
    int tb = (int)(tb1 * (1-u) + tb2 * u);
    
	return new int[]{tr, tg, tb};
}
四:运行效果


五:类ShearFilter完整代码

package com.gloomyfish.filter.study;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;

public class ShearFilter extends AbstractBufferedImageOp {
	private int outw;
	private int outh;
	private double angle;
	private Color backgroundColor;
	private boolean vertical;
	
	public void setVertical(boolean vertical) {
		this.vertical = vertical;
	}

	public ShearFilter()
	{
		backgroundColor = Color.BLACK;
		vertical = false;
		this.angle = 20;
	}
	
	public int getOutw() {
		return outw;
	}
	public void setOutw(int outw) {
		this.outw = outw;
	}
	public int getOuth() {
		return outh;
	}
	public void setOuth(int outh) {
		this.outh = outh;
	}
	public double getAngle() {
		return angle;
	}
	public void setAngle(double angle) {
		this.angle = angle;
	}
	public Color getBackgroundColor() {
		return backgroundColor;
	}
	public void setBackgroundColor(Color backgroundColor) {
		this.backgroundColor = backgroundColor;
	}
	@Override
	public BufferedImage filter(BufferedImage src, BufferedImage dest) {
		int width = src.getWidth();
        int height = src.getHeight();

        double angleValue = (angle/180.0d) * Math.PI;
        outh = vertical ? (int)(height + width * Math.tan(angleValue)) : height;
        outw = vertical ? width : (int)(width + height * Math.tan(angleValue));
        System.out.println("after shear, new width : " + outw);
        System.out.println("after shear, new height: " + outh);
        
        int[] inPixels = new int[width*height];
        int[] outPixels = new int[outh*outw];
        getRGB( src, 0, 0, width, height, inPixels );
        int index = 0;
        for(int row=0; row<outh; row++) {
        	int ta = 0;
        	for(int col=0; col<outw; col++) {
				double prow = vertical ? row + Math.tan(angleValue) * (col - width) : row;
				double pcol = vertical ? col : col + Math.tan(angleValue) * (row - height);
        		int[] rgb = getPixel(inPixels, width, height, prow, pcol);
        		index = row * outw + col;
        		outPixels[index] = (ta << 24) | (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];  
        	}
        }

        if ( dest == null )
        	dest = createCompatibleDestImage( src, null );
        setRGB( dest, 0, 0, outw, outh, outPixels );
        return dest;
	}

	private int[] getPixel(int[] input, int width, int height, 
			double prow, double pcol) {
		double row = Math.floor(prow);
		double col = Math.floor(pcol);
		if(row < 0 || row >= height) {
			return new int[]{backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue()};
		}
		if(col < 0 || col >= width) {
			return new int[]{backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue()};
		}
		double u = vertical ? (prow - row) : pcol - col;
		int nextCol = (int)(col + 1);
		int nextRow = (int)(row + 1);
		if((col + 1) >= width) {
			nextCol = (int)col;
		}
		if((row + 1) >= height) {
			nextRow = (int)row;
		}
		int index1 = (int)(row * width + col);
		int index2 = vertical ? (int)(nextRow * width + col) : (int)(row * width + nextCol);
		
		int tr1, tr2;
		int tg1, tg2;
		int tb1, tb2;
		
        tr1 = (input[index1] >> 16) & 0xff;
        tg1 = (input[index1] >> 8) & 0xff;
        tb1 = input[index1] & 0xff;
        
        tr2 = (input[index2] >> 16) & 0xff;
        tg2 = (input[index2] >> 8) & 0xff;
        tb2 = input[index2] & 0xff;
        
        int tr = (int)(tr1 * (1-u) + tr2 * u);
        int tg = (int)(tg1 * (1-u) + tg2 * u);
        int tb = (int)(tb1 * (1-u) + tb2 * u);
        
		return new int[]{tr, tg, tb};
	}
	
    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
        if ( dstCM == null )
            dstCM = src.getColorModel();
        return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(outw, outh), dstCM.isAlphaPremultiplied(), null);
    }

}
下半年事情比较多,博客一直没有更新,感谢众多网友的关注与留言

我会继续努力的!再次声明一下:请不要向我索取源码!谢谢!

代码我在整理中,最终我会开源让大家自己下载,请耐心等待!

目录
相关文章
|
5月前
|
机器学习/深度学习 人工智能 算法
大型多模态推理模型技术演进综述:从模块化架构到原生推理能力的综合分析
该研究系统梳理了大型多模态推理模型(LMRMs)的技术发展,从早期模块化架构到统一的语言中心框架,提出原生LMRMs(N-LMRMs)的前沿概念。论文划分三个技术演进阶段及一个前瞻性范式,深入探讨关键挑战与评估基准,为构建复杂动态环境中的稳健AI系统提供理论框架。未来方向聚焦全模态泛化、深度推理与智能体行为,推动跨模态融合与自主交互能力的发展。
287 13
大型多模态推理模型技术演进综述:从模块化架构到原生推理能力的综合分析
|
Windows
关于:未能加载文件或程序集“ICSharpCode.SharpZipLib”或它的某一个依赖项异常的解决方案
关于:未能加载文件或程序集“ICSharpCode.SharpZipLib”或它的某一个依赖项异常的解决方案
1178 0
|
11月前
|
运维 Java 编译器
Java 异常处理:机制、策略与最佳实践
Java异常处理是确保程序稳定运行的关键。本文介绍Java异常处理的机制,包括异常类层次结构、try-catch-finally语句的使用,并探讨常见策略及最佳实践,帮助开发者有效管理错误和异常情况。
772 6
|
11月前
|
SQL 数据库 开发者
达梦数据库 【-6111: 字符串转换出错】问题处理
在更新数据库某个值属性时,遇到了“字符串转换出错”的错误。经过分析,发现是由于 `id` 字段实际上是字符串类型而非数值类型导致的。最终通过将 `id` 的值改为字符串类型解决了问题。此问题提醒我们在处理数据库时要仔细检查表结构,不要凭经验臆断字段类型。
|
程序员
老程序员分享:Lua的unpack
老程序员分享:Lua的unpack
446 0
|
11月前
|
存储 监控 安全
数据泄露后的应对措施:个人和企业的行动指南
数据泄露后的应对措施:个人和企业的行动指南
1045 2
|
存储 监控 安全
端口安全:交换机上的网络守护者
【8月更文挑战第27天】
297 1
|
SQL 关系型数据库 MySQL
在Linux中,mysql 数据备份工具有哪些?
在Linux中,mysql 数据备份工具有哪些?
|
人工智能 数据库
故事与绘本Bot-扣子AI
**摘要:** 构建了一个结合互动与故事讲解的语音交流Bot,灵感源于减轻教师姐姐夜间给小外甥讲故事的负担。该Bot以“小芸”角色引导用户创作故事,包括主题、情节、角色、背景等要素,并通过LLM模型生成故事内容。工作流程包括输入参数、文章生成、关键字提取和优化、以及相关图片生成。下一步计划支持微信集成、预设故事数据库及绘本图像优化。商业上,考虑将其集成到儿童故事设备和抖音账号,打造自动化故事分享平台。
故事与绘本Bot-扣子AI
|
编解码 缓存 算法
【计算机图形学】期末复习,选择题+判断题篇
【计算机图形学】期末复习,选择题+判断题篇