在R中保存旋转图像-避免背景并保持尺寸

用户名

我下面的代码是基于我之前的问题当我保存图像SaveThisPlot.png时,它会创建不需要的背景,并且图像尺寸也会更改(减小)。如何保存图像,使旋转后的部分与以前的大小完全相同(77行和101列)并且没有背景?

library(raster)
r1 <- brick(system.file("external/rlogo.grd", package="raster"))
r1
x <- crop(r1, extent(0,ncol(r1),0,nrow(r1)))
plotRGB(x)

x1 <- 0:ncol(x)
y1 <- 0:nrow(x)
z <- matrix(1, nrow=length(x1), ncol=length(y1))

col.mat <- t(apply(matrix(rgb(getValues(x)/255), nrow=nrow(x), byrow=TRUE), 2, rev))

# Rotate 45 degrees
persp(x1, y1, z, zlim=c(0,2), theta = 20, phi = 90, 
      col = col.mat, scale=FALSE, border=NA, box=FALSE)
png("SaveThisPlot.png")
persp(x1, y1, z, zlim=c(0,2), theta = 20, phi = 90, 
      col = col.mat, scale=FALSE, border=NA, box=FALSE)
dev.off()

在此处输入图片说明

您可以使用透明背景,但是旋转图将需要调整大小。

保存绘图时,可以进行设置png("SaveThisPlot.png", bg="transparent")以防止显示背景。尝试:

png("SaveThisPlot.png", width=101 height=77, units="px", pointsize=1, bg="transparent")

请注意,如果您尝试使用徽标的旋转版本来进行此操作,则会将徽标的大小调整为适合101 x 77像素png的大小。如果要旋转它并保持徽标大小,则必须调整png的大小,在评论中提及@@RomanLuštrik。调整大小(如果您可以这样做)仅是三角函数,即可找到合适的高度和宽度参数。

您可以尝试设置新的高度和宽度,以使用某些三角函数保存png。这是一个35度旋转的示例:

# hypotenuse
hypot <- sqrt((nrow(x)/2)^2 + (ncol(x)/2)^2) 
# angle
angle <- asin((nrow(x)/2)/ hypot)/(pi/180)

width <- 2 * max(abs(hypot * cos((angle + 35) * pi/180)), 
                 abs(hypot * cos((- angle + 35) * pi/180)))

height <- 2 * max(abs(hypot * sin((angle + 35) * pi/180)), 
                 abs(hypot * sin((- angle + 35) * pi/180)))


png("SaveThisPlot.png", height=height, width=width, units="px", pointsize=1,
    bg="transparent")
par(mar=c(0,0,0,0), xaxs = "i", yaxs = "i")
persp(x1, y1, z, zlim=c(0,2), theta = 35, phi = 90, 
      col = col.mat, scale=FALSE, border=NA, box=FALSE)
dev.off()

在此处输入图片说明

整体图像将不是77 x 101像素,但徽标本身应具有相同的大小,尽管有点粗糙。要获得更平滑的图像,请参见rgl下面答案,但请注意,透明背景不适用于rgl

使用rgl软件包的替代方法:

如果最终目标是保持图像的大小和平滑度,则采用其他方法生成图像可能会更好。您可以尝试使用rgl(R-to-OpenGL)软件包和persp3d功能,在其中可以在不改变窗口大小或更改徽标比例的情况下在其窗口内旋转绘图。您通常可以使用已有的东西,但是需要修改颜色矩阵才能使用persp3d

col.mat2 <- cbind(rbind(1, col.mat), 1)

然后,设置场景,调用persp3d,旋转场景并保存。

open3d() 
rgl.pop("lights") 
light3d(specular="black") # to reduce reflection
persp3d(x1,y1,z, col=col.mat2, ylab="", xlab="", zlab="",
        axes=FALSE, smooth=FALSE, aspect="iso")

# Rotate it by defining the userMatrix, then save    
par3d(userMatrix = rotationMatrix(0*pi/180, 0, 0, 1))
rgl.snapshot("Rlogo_0.png") # to save

par3d(userMatrix = rotationMatrix(45*pi/180, 0, 0, 1))
rgl.snapshot("Rlogo_45.png")

par3d(userMatrix = rotationMatrix(135*pi/180, 0, 0, 1))
rgl.snapshot("Rlogo_135.png")

RlogoRlogo_45度Rlog_135度

To force this image into a smaller window, you can manipulate the size of the rgl display window and the amount of background using a combination of the windowRect and zoom parameters (See this question and answer, for example). However, a transparent background isn't an option with rgl currently.

open3d()
bg3d(color="#FF00FF") # pink background (some color not in the actual image)
rgl.pop("lights") 
light3d(specular="black") 
persp3d(x1,y1,z, col=col.mat2, axes=FALSE,
     ylab="", xlab="", zlab="", smooth=FALSE, aspect="iso")
rgl.viewpoint(zoom=0.52)
par3d(userMatrix = rotationMatrix(0*pi/180, 0, 0, 1), windowRect=c(0,0, 101, 77))
rgl.snapshot("Rlogo_77h124w.png")
par3d(userMatrix = rotationMatrix(45*pi/180, 0, 0, 1), windowRect=c(0,0, 101, 77))
rgl.snapshot("Rlogo45_77h124w.png")

I wasn't able to make the window any less than 124 pixels wide. It seems there is a minimum width of 124 pixels to an rgl window on my computer, as I can't make the window any smaller (i.e. can't collapse the minimize, restore, and close buttons on top of the window).

在此处输入图片说明 在此处输入图片说明

To get a transparent background, you could import these saved pngs, and assign alpha values of 1 to the background color ("#FF69B4"):

library(png)
add.alpha <- readPNG("Rlogo_77h124w.png") #Try a rotate version, too

library(abind)
add.alpha <- abind(add.alpha, matrix(1, nrow=nrow(add.alpha), ncol=ncol(add.alpha)))

add.alpha[,,4][which(rgb(add.alpha[,,1],add.alpha[,,2],add.alpha[,,3]) == "#FF00FF")] <- 0
writePNG(add.alpha, "Rlogo_77h124w_alpha.png")

事实证明,这种方法并不完美,您可能会在旋转的图像上出现一个略微的边框,而该图像的颜色并不完全是“#FF00FF”。如果这对您来说是一个问题,您可以采用一种或另一种方式处理边界,但这可能不会有所不同,具体取决于最终目标。尝试使用add.alpha[,,4][which(add.alpha[,,1] > .9 & add.alpha[,,3] > .9 & add.alpha[,,2] < .85 )] <- 0之前writePNG

在此处输入图片说明在此处输入图片说明在此处输入图片说明

如果您不希望像上面那样切掉图像的角,请使用前面的三角函数来帮助在以下范围内正确调整窗口大小par3d

open3d(); bg3d(color="#FF69B4"); rgl.pop("lights"); light3d(specular="black") 
persp3d(x1,y1,z, col=col.mat2, axes=FALSE,
     ylab="", xlab="", zlab="", smooth=FALSE, aspect="iso")
view3d(zoom=.862)
par3d(userMatrix = rotationMatrix(-45*pi/180, 0, 0, 1), windowRect=c(0,0, width, height)) # width and height from trigonometry above
rgl.snapshot("Rlogo45_77h124w.png")
#library(png)
add.alpha <- readPNG("Rlogo45_77h124w.png") # Try "Rlogo_77h124w.png", too
#library(abind)
add.alpha <- abind(add.alpha, matrix(1, nrow=nrow(add.alpha), ncol=ncol(add.alpha)))

add.alpha[,,4][which(add.alpha[,,1] > .9 & add.alpha[,,3] > .9 & add.alpha[,,2] < .85 )] <- 0 # not a perfect solution
writePNG(add.alpha, "Rlogo45_77h124w_alpha.png")

在此处输入图片说明

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章