图像处理之错切变换

简介: 图像处理之错切变换

图像处理之错切变换

一:基本数学知识:

图像错切变换在图像几何形变方面非常有用,常见的错切变换分为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);
    }
 
}

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

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

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

相关文章
|
JavaScript
vant/vue——在van-tab中写入内容使其中间部分进行滚动
在van-tab中写入内容使其中间部分进行滚动
689 0
|
iOS开发
iOS 审核 2.3.3 被拒解决办法
iOS 审核 2.3.3 被拒解决办法
1131 0
|
9月前
|
机器学习/深度学习 测试技术 网络架构
YOLOv5改进 | 主干篇 | ConvNeXtV2全卷积掩码自编码器网络
YOLOv5改进 | 主干篇 | ConvNeXtV2全卷积掩码自编码器网络
342 0
|
7月前
|
存储 监控 安全
ERP系统中的用户权限与安全管理
【7月更文挑战第25天】 ERP系统中的用户权限与安全管理
627 2
|
Java 数据库连接 数据库
Mybatis系列(四)之Mybatis与Spring整合以及Aop整合pagehelper插件
Mybatis系列(四)之Mybatis与Spring整合以及Aop整合pagehelper插件
|
存储 分布式计算 Cloud Native
突破次元壁,Ganos Aero加速空天大数据处理进入云原生算力时代
阿里云瑶池数据库团队推出了空天大数据管理技术方案Ganos Aero,帮助用户高效搭建空天大数据管理平台,提升空天数据处理效率,降低管理成本。
70112 221
|
消息中间件 存储 Java
ELK,彻底解决集群项目的日志查看问题(一)
每当项目上线时,因为项目是集群部署的,所以,来回到不同的服务器上查看日志会变得很麻烦,你是不是也碰到这样类似的问题,那么ELK将能解决你遇到的问题!
ELK,彻底解决集群项目的日志查看问题(一)
|
Python
【Python】使用TUNA提升pip安装第3方包的速度
【Python】使用TUNA提升pip安装第3方包的速度
274 0
|
关系型数据库 MySQL 应用服务中间件
【阿里云-轻量服务器】LNMP网站架构部署最佳实践分享
【阿里云-轻量服务器】LNMP网站架构部署最佳实践分享
|
9月前
|
网络架构
YOLOv5改进 | 2023主干篇 | 利用RT-DETR特征提取网络PPHGNetV2改进YOLOv5(超级轻量化精度更高)
YOLOv5改进 | 2023主干篇 | 利用RT-DETR特征提取网络PPHGNetV2改进YOLOv5(超级轻量化精度更高)
392 0

热门文章

最新文章