R - 根据不同的角度和原点旋转数据框中的坐标

R - Rotate coordinates in dataframe based on varying angles and origin

我有一个数据框 data 有几列,包括 ID Image(重复几行)和 X CenterX_um 和 Y CenterY_um 坐标(每行不同).

我想根据每个 ID 特定的角度和原点旋转 X、Y 坐标。我在单独的数据框 rotation_info.

上也有此信息

我试过 rearrr::rotate_2d 功能,但它不允许我指定角度和原点。相反,它希望对所有人使用相同的角度和原点。

有什么线索吗?

这是每个数据帧的子集:

data <- structure(list(Image = c("P112_SOD1_scene-01_roi1", "P112_SOD1_scene-01_roi1", "P112_SOD1_scene-01_roi1", "P112_SOD1_scene-03_roi1",
                         "P112_SOD1_scene-03_roi1", "P112_SOD1_scene-03_roi1", "P112_SOD1_scene-08_roi1", "P112_SOD1_scene-08_roi1", 
                         "P112_SOD1_scene-14_roi1", "P112_SOD1_scene-14_roi1", "P112_WT_scene-13_roi1", "P112_WT_scene-13_roi1"),
               Area_pixel2 = c(6172L, 2804L, 4133L, 1547L, 9224L, 5133L, 4311L, 2740L, 2610L, 3802L, 5129L, 4106L),
               Area_um2 = c(318.03702442715, 144.48733254921, 212.96938139297, 79.715372130394, 475.30355044005, 264.49838729497, 222.14154444352, 
                            141.18947617148, 134.49070540422, 195.91328043941, 264.29227127136, 211.57809823361),
               CenterX_um = c(1149.8904493589, 1126.4609300602, 1100.8211294593, 1024.1176019595, 993.32875148771, 964.51498442025, 874.9485394368,
                              843.03397382692, 1457.7886911485, 1359.4372824824, 1549.4154976822, 1614.8843949665),
               CenterY_um = c(65.734010569428, 87.806098466489, 121.24362888879, 344.12182158201, 349.1125830895, 378.36327230154, 222.10103046474,
                              236.8534704986, 524.97197144378, 536.26329031132, 101.93303030628, 103.3766130805),
               Circularity = c(0.70514719268137, 0.73725777209061, 0.55904614141807, 0.64491724919754, 0.72628772170604, 0.68836548793912,
                               0.80455000787307, 0.75794971514553, 0.58945714820048, 0.75891540252167, 0.63520099709918, 0.79151119246911),
               Compactness = c(0.66065335617958, 0.64189735971181, 0.53383026406418, 0.53076228622962, 0.76004630952984, 0.72584335956662,
                               0.81606076244974, 0.77264654886067, 0.51250290104024, 0.78515382913133, 0.66035724052464, 0.80977712999347)),
          row.names = c(1L, 2L, 3L, 1505L, 1506L, 1507L, 8500L, 8501L, 15689L, 15690L, 30001L, 30002L), class = "data.frame")

data
#                        Image Area_pixel2  Area_um2 CenterX_um CenterY_um Circularity Compactness
#1     P112_SOD1_scene-01_roi1        6172 318.03702  1149.8904   65.73401   0.7051472   0.6606534
#2     P112_SOD1_scene-01_roi1        2804 144.48733  1126.4609   87.80610   0.7372578   0.6418974
#3     P112_SOD1_scene-01_roi1        4133 212.96938  1100.8211  121.24363   0.5590461   0.5338303
#1505  P112_SOD1_scene-03_roi1        1547  79.71537  1024.1176  344.12182   0.6449172   0.5307623
#1506  P112_SOD1_scene-03_roi1        9224 475.30355   993.3288  349.11258   0.7262877   0.7600463
#1507  P112_SOD1_scene-03_roi1        5133 264.49839   964.5150  378.36327   0.6883655   0.7258434
#8500  P112_SOD1_scene-08_roi1        4311 222.14154   874.9485  222.10103   0.8045500   0.8160608
#8501  P112_SOD1_scene-08_roi1        2740 141.18948   843.0340  236.85347   0.7579497   0.7726465
#15689 P112_SOD1_scene-14_roi1        2610 134.49071  1457.7887  524.97197   0.5894571   0.5125029
#15690 P112_SOD1_scene-14_roi1        3802 195.91328  1359.4373  536.26329   0.7589154   0.7851538
#30001   P112_WT_scene-13_roi1        5129 264.29227  1549.4155  101.93303   0.6352010   0.6603572
#30002   P112_WT_scene-13_roi1        4106 211.57810  1614.8844  103.37661   0.7915112   0.8097771
rotation_info <- structure(list(Image = c("P112_SOD1_scene-01_roi1", "P112_SOD1_scene-03_roi1", 
"P112_SOD1_scene-08_roi1", "P112_SOD1_scene-14_roi1", "P112_WT_scene-13_roi1"
), Angle = c(199.289658091447, 202.184697711029, 158.990932730799, 
180.612494033135, 15.223442470483), CC_X = c(989.039056641, 970.652055588, 
1104.355063245, 781.334044746, 1034.893059267), CC_Y = c(792.457045383, 
798.359045721, 940.915053885, 747.057042783, 709.829040651)), row.names = c(NA, 
-5L), class = "data.frame")

rotation_info
#                    Image     Angle      CC_X     CC_Y
#1 P112_SOD1_scene-01_roi1 199.28966  989.0391 792.4570
#2 P112_SOD1_scene-03_roi1 202.18470  970.6521 798.3590
#3 P112_SOD1_scene-08_roi1 158.99093 1104.3551 940.9151
#4 P112_SOD1_scene-14_roi1 180.61249  781.3340 747.0570
#5   P112_WT_scene-13_roi1  15.22344 1034.8931 709.8290

我的想法是首先基于 Image 合并两个数据帧,以便为每一行复制角度和原点(这很有效),然后将 rearrr::rotate_2d 函数应用于每个排。这是我 运行 遇到麻烦的时候,因为它需要所有行的相同角度和原点。

# Merge rotation info into data
data <- merge(data, rotation_info, by="Image", all.x=TRUE)

# Rotate based on angle ("Angle") and origin ("CC_X", "CC_Y")
data <- rotate_2d(data, degrees = data$Angle, x_col = "CenterX_um", y_col = "CenterY_um",
                  origin = c(data$CC_X, data$CC_Y) , suffix = "", overwrite = TRUE)

欢迎任何其他方法。我不一定需要我的数据框中的旋转信息(实际上我打算在之后删除它)。

提前致谢!

似乎 rearrr::rotate_2d() 并不是真正设计用于以您尝试的方式从源数据中获取 degreesorigin 参数。如果这样做,它将每隔 Angle 围绕每个 origin.

旋转每个点

相反,我使用 purrr::group_map()Image 拆分数据,并使用单个 degreesorigin 参数分别对每个数据进行操作(由 mean(., na.rm = T) 尽管您可以使用 unique()min() 或其他任何东西来获取单个值而不是重复值的向量)。

见底部的图,我分别用红色和蓝色显示原始点和旋转点,每个点的原点都带有 *.

library(tidyverse)
library(rearrr)

data <- structure(list(Image = c("P112_SOD1_scene-01_roi1", "P112_SOD1_scene-01_roi1", "P112_SOD1_scene-01_roi1", "P112_SOD1_scene-03_roi1",
                                 "P112_SOD1_scene-03_roi1", "P112_SOD1_scene-03_roi1", "P112_SOD1_scene-08_roi1", "P112_SOD1_scene-08_roi1", 
                                 "P112_SOD1_scene-14_roi1", "P112_SOD1_scene-14_roi1", "P112_WT_scene-13_roi1", "P112_WT_scene-13_roi1"),
                       Area_pixel2 = c(6172L, 2804L, 4133L, 1547L, 9224L, 5133L, 4311L, 2740L, 2610L, 3802L, 5129L, 4106L),
                       Area_um2 = c(318.03702442715, 144.48733254921, 212.96938139297, 79.715372130394, 475.30355044005, 264.49838729497, 222.14154444352, 
                                    141.18947617148, 134.49070540422, 195.91328043941, 264.29227127136, 211.57809823361),
                       CenterX_um = c(1149.8904493589, 1126.4609300602, 1100.8211294593, 1024.1176019595, 993.32875148771, 964.51498442025, 874.9485394368,
                                      843.03397382692, 1457.7886911485, 1359.4372824824, 1549.4154976822, 1614.8843949665),
                       CenterY_um = c(65.734010569428, 87.806098466489, 121.24362888879, 344.12182158201, 349.1125830895, 378.36327230154, 222.10103046474,
                                      236.8534704986, 524.97197144378, 536.26329031132, 101.93303030628, 103.3766130805),
                       Circularity = c(0.70514719268137, 0.73725777209061, 0.55904614141807, 0.64491724919754, 0.72628772170604, 0.68836548793912,
                                       0.80455000787307, 0.75794971514553, 0.58945714820048, 0.75891540252167, 0.63520099709918, 0.79151119246911),
                       Compactness = c(0.66065335617958, 0.64189735971181, 0.53383026406418, 0.53076228622962, 0.76004630952984, 0.72584335956662,
                                       0.81606076244974, 0.77264654886067, 0.51250290104024, 0.78515382913133, 0.66035724052464, 0.80977712999347)),
                  row.names = c(1L, 2L, 3L, 1505L, 1506L, 1507L, 8500L, 8501L, 15689L, 15690L, 30001L, 30002L), class = "data.frame")


rotation_info <- structure(list(Image = c("P112_SOD1_scene-01_roi1", "P112_SOD1_scene-03_roi1", 
                                          "P112_SOD1_scene-08_roi1", "P112_SOD1_scene-14_roi1", "P112_WT_scene-13_roi1"), 
                                Angle = c(199.289658091447, 202.184697711029, 158.990932730799, 180.612494033135, 15.223442470483), 
                                CC_X = c(989.039056641, 970.652055588, 1104.355063245, 781.334044746, 1034.893059267), 
                                CC_Y = c(792.457045383, 798.359045721, 940.915053885, 747.057042783, 709.829040651)), 
                           row.names = c(NA, -5L), class = "data.frame")

# Merge rotation info into data
data2 <- merge(data, rotation_info, by="Image", all.x=TRUE)

# rotate each image by its respective origin and angle
data3 <- data2 %>%
  group_by(Image) %>%
  group_map(
    ~ rotate_2d(
      data = .,
      degrees = mean(.[["Angle"]], na.rm = T),
      x_col = "CenterX_um",
      y_col = "CenterY_um",
      origin = c(mean(.[["CC_X"]], na.rm = T), mean(.[["CC_Y"]], na.rm = T)), 
      keep_original = TRUE
    ),
    .keep = T
  ) %>% 
  bind_rows()

# visualize rotated result vs original
data3 %>% 
  select(Image, CC_X:CC_Y, starts_with("Center")) %>% 
  group_by(Image) %>% 
  mutate(point_id = row_number()) %>% 
  ungroup() %>% 
  pivot_longer(
    cols = -c(Image, point_id, CC_X, CC_Y),
    names_to = c("axis", "units", "rotation"),
    names_prefix = "Center",
    names_sep = "_",
    values_to = "position"
  ) %>% 
  replace_na(list(rotation = "original")) %>% 
  pivot_wider(names_from = axis, values_from = position) %>% 
  ggplot(aes(X, Y, color = rotation)) +
  geom_point() +
  geom_path() +
  geom_point(aes(CC_X, CC_Y), size = 4, color = "black", shape = 8) +
  facet_wrap(~Image, scales = "free")
#> Warning: Expected 3 pieces. Missing pieces filled with `NA` in 2 rows [1, 2].

reprex package (v2.0.1)

于 2022-01-27 创建