简体   繁体   English

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

[英]saving rotate images in R - avoiding background and maintaining size

I have below code which is based upon my earlier question .我有以下代码,它基于我之前的问题 When I save the image SaveThisPlot.png, it creates unwanted background and the image size also changes (it reduces).当我保存图像 SaveThisPlot.png 时,它会创建不需要的背景并且图像大小也会改变(它会减小)。 How can i save the image such that the rotated part is of exactly same size as earlier (77 rows and 101 columns) and there is no background?如何保存图像,使旋转部分的大小与之前完全相同(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()

在此处输入图片说明

You can use a transparent background, but rotating the plot will require re-sizing.您可以使用透明背景,但旋转绘图需要重新调整大小。

When you save your plot you can set png("SaveThisPlot.png", bg="transparent") to prevent a background from showing.保存绘图时,您可以设置png("SaveThisPlot.png", bg="transparent")以防止显示背景。 Try:尝试:

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

Notice if you try to do this with a rotated version of the logo, the logo is re-sized to fit within the 101 x 77 pixel png.请注意,如果您尝试使用旋转版本的徽标来执行此操作,徽标会重新调整大小以适合 101 x 77 像素 png。 If you want to rotate it and maintain the logo size, you'll have to resize the png, ass @RomanLuštrik mentioned in his comment.如果您想旋转它并保持徽标大小,则必须调整 png 的大小,@RomanLuštrik 在他的评论中提到。 Re-sizing, if that is an option for you, is just a matter of trigonometry to find the appropriate height and width parameters.重新调整大小,如果这对你来说是一个选项,只是一个三角函数的问题,以找到合适的高度和宽度参数。

You can try setting new heights and widths to save the png using some trigonometry.您可以尝试使用一些三角函数设置新的高度和宽度以保存 png。 Here is an example with 35 degrees of rotation:这是一个旋转 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()

在此处输入图片说明

The overall image will be not be 77 x 101 pixels, but the logo itself should be the same size, though a bit rugged.整体图像不会是 77 x 101 像素,但徽标本身应该是相同的大小,虽然有点粗糙。 For a smoother image, see the rgl answer below, but note that a transparent background isn't available for rgl要获得更平滑的图像,请参阅下面的rgl答案,但请注意,透明背景不适用于rgl

Alternative approach using the rgl package:使用 rgl 包的替代方法:

A different approach to producing the image might be better if the end goal is to maintain the size and smoothness of the image.如果最终目标是保持图像的大小和平滑度,则生成图像的不同方法可能会更好。 You can try the rgl (R-to-OpenGL) package and the persp3d function, where you can rotate the plot within its window without re-sizing the window or altering the proportions of the logo.您可以尝试使用rgl (R-to-OpenGL) 包和persp3d函数,您可以在其中旋转其窗口内的绘图,而无需重新调整窗口大小或更改徽标的比例。 You can mostly use what you've already got, but the color matrix needs to be modified to work with persp3d :您主要可以使用已有的东西,但需要修改颜色矩阵才能与persp3d一起persp3d

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

Then, set the scene, call persp3d , rotate it, and save.然后,设置场景,调用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")

标志Rlogo_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 ).要强制将此图像放入较小的窗口,您可以使用windowRectzoom参数的组合来操纵 rgl 显示窗口的大小和背景量( 例如,请参阅此问答)。 However, a transparent background isn't an option with rgl currently.但是,透明背景目前不是rgl的选项。

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.我无法使窗口宽度小于 124 像素。 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 (ie can't collapse the minimize, restore, and close buttons on top of the window).似乎我的计算机上的 rgl 窗口的最小宽度为 124 像素,因为我无法使窗口变小(即无法折叠窗口顶部的最小化、恢复和关闭按钮)。

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

To get a transparent background, you could import these saved pngs, and assign alpha values of 1 to the background color ("#FF69B4"):要获得透明背景,您可以导入这些保存的 png,并将 alpha 值 1 分配给背景颜色(“#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")

It turns out this method isn't perfect, and you may end up with a slight border on rotated images where the color isn't exactly "#FF00FF".事实证明,这种方法并不完美,您最终可能会在颜色不完全是“#FF00FF”的旋转图像上出现轻微边框。 You can address the border one way or another, if it is a problem for you, but it may not make a difference depending on the end goals.您可以通过一种或另一种方式解决边界问题,如果这对您来说是个问题,但根据最终目标,它可能不会产生影响。 Try using add.alpha[,,4][which(add.alpha[,,1] > .9 & add.alpha[,,3] > .9 & add.alpha[,,2] < .85 )] <- 0 before writePNG尝试使用add.alpha[,,4][which(add.alpha[,,1] > .9 & add.alpha[,,3] > .9 & add.alpha[,,2] < .85 )] <- 0writePNG之前

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

If you don't want the image corners cut off like above, then use the trigonometry from earlier to help size the window properly within par3d :如果您不希望像上面那样切掉图像角,请使用前面的三角函数来帮助在par3d内正确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")

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM